source: Dev/trunk/RGraph/libraries/RGraph.pie.js @ 77

Last change on this file since 77 was 77, checked in by fpvanagthoven, 14 years ago

RGraph

File size: 33.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 pie chart constructor
19    *
20    * @param data array The data to be represented on the pie chart
21    */
22    RGraph.Pie = function (id, data)
23    {
24        this.id                = id;
25        this.canvas            = document.getElementById(id);
26        this.context           = this.canvas.getContext("2d");
27        this.canvas.__object__ = this;
28        this.total             = 0;
29        this.subTotal          = 0;
30        this.angles            = [];
31        this.data              = data;
32        this.properties        = [];
33        this.type              = 'pie';
34        this.isRGraph          = true;
35
36
37        /**
38        * Compatibility with older browsers
39        */
40        RGraph.OldBrowserCompat(this.context);
41
42        this.properties = {
43            'chart.colors':                 ['rgb(255,0,0)', '#ddd', 'rgb(0,255,0)', 'rgb(0,0,255)', 'pink', 'yellow', '#000'],
44            'chart.strokestyle':            '#999',
45            'chart.linewidth':              1,
46            'chart.labels':                 [],
47            'chart.labels.sticks':          false,
48            'chart.labels.sticks.color':    '#aaa',
49            'chart.segments':               [],
50            'chart.gutter.left':            25,
51            'chart.gutter.right':           25,
52            'chart.gutter.top':             25,
53            'chart.gutter.bottom':          25,
54            'chart.title':                  '',
55            'chart.title.background':       null,
56            'chart.title.hpos':             null,
57            'chart.title.vpos':             null,
58            'chart.shadow':                 false,
59            'chart.shadow.color':           'rgba(0,0,0,0.5)',
60            'chart.shadow.offsetx':         3,
61            'chart.shadow.offsety':         3,
62            'chart.shadow.blur':            3,
63            'chart.text.size':              10,
64            'chart.text.color':             'black',
65            'chart.text.font':              'Verdana',
66            'chart.contextmenu':            null,
67            'chart.tooltips':               [],
68            'chart.tooltips.event':         'onclick',
69            'chart.tooltips.effect':        'fade',
70            'chart.tooltips.css.class':     'RGraph_tooltip',
71            'chart.tooltips.highlight':     true,
72            'chart.highlight.style':        '3d',
73            'chart.highlight.style.2d.fill': 'rgba(255,255,255,0.5)',
74            'chart.highlight.style.2d.stroke': 'rgba(255,255,255,0)',
75            'chart.radius':                 null,
76            'chart.border':                 false,
77            'chart.border.color':           'rgba(255,255,255,0.5)',
78            'chart.key':                    null,
79            'chart.key.background':         'white',
80            'chart.key.position':           'graph',
81            'chart.key.halign':             'right',
82            'chart.key.shadow':             false,
83            'chart.key.shadow.color':       '#666',
84            'chart.key.shadow.blur':        3,
85            'chart.key.shadow.offsetx':     2,
86            'chart.key.shadow.offsety':     2,
87            'chart.key.position.gutter.boxed': true,
88            'chart.key.position.x':         null,
89            'chart.key.position.y':         null,
90            'chart.key.color.shape':        'square',
91            'chart.key.rounded':            true,
92            'chart.key.linewidth':          1,
93            'chart.annotatable':            false,
94            'chart.annotate.color':         'black',
95            'chart.align':                  'center',
96            'chart.zoom.factor':            1.5,
97            'chart.zoom.fade.in':           true,
98            'chart.zoom.fade.out':          true,
99            'chart.zoom.hdir':              'right',
100            'chart.zoom.vdir':              'down',
101            'chart.zoom.frames':            10,
102            'chart.zoom.delay':             50,
103            'chart.zoom.shadow':            true,
104            'chart.zoom.mode':              'canvas',
105            'chart.zoom.thumbnail.width':   75,
106            'chart.zoom.thumbnail.height':  75,
107            'chart.zoom.background':        true,
108            'chart.zoom.action':            'zoom',
109            'chart.resizable':              false,
110            'chart.resize.handle.adjust':   [0,0],
111            'chart.resize.handle.background': null,
112            'chart.variant':                'pie',
113            'chart.variant.donut.color':    'white',
114            'chart.exploded':               []
115        }
116
117        /**
118        * Calculate the total
119        */
120        for (var i=0,len=data.length; i<len; i++) {
121            this.total += data[i];
122        }
123
124
125        /**
126        * Set the .getShape commonly named method
127        */
128        this.getShape = this.getSegment;
129    }
130
131
132    /**
133    * A generic setter
134    */
135    RGraph.Pie.prototype.Set = function (name, value)
136    {
137        if (name == 'chart.highlight.style.2d.color') {
138            name = 'chart.highlight.style.2d.fill';
139        }
140
141        this.properties[name] = value;
142    }
143
144
145    /**
146    * A generic getter
147    */
148    RGraph.Pie.prototype.Get = function (name)
149    {
150        if (name == 'chart.highlight.style.2d.color') {
151            name = 'chart.highlight.style.2d.fill';
152        }
153
154        return this.properties[name];
155    }
156
157
158    /**
159    * This draws the pie chart
160    */
161    RGraph.Pie.prototype.Draw = function ()
162    {
163        /**
164        * Fire the onbeforedraw event
165        */
166        RGraph.FireCustomEvent(this, 'onbeforedraw');
167
168       
169        /**
170        * This bit of code converts chart.exploded from an integer to an array
171        * that consists of that value, repeated n times, where n is equal to
172        * the number of segments that you have
173        */
174        var explosion = this.Get('chart.exploded');
175        if (typeof(explosion) == 'number') {
176            this.Set('chart.exploded', RGraph.array_pad([], this.data.length, explosion));
177        }
178
179        /**
180        * This is new in May 2011 and facilitates indiviual gutter settings,
181        * eg chart.gutter.left
182        */
183        this.gutterLeft   = this.Get('chart.gutter.left');
184        this.gutterRight  = this.Get('chart.gutter.right');
185        this.gutterTop    = this.Get('chart.gutter.top');
186        this.gutterBottom = this.Get('chart.gutter.bottom');
187
188        /**
189        * Reset this to an empty array
190        */
191        this.Set('chart.segments', []);
192
193        /**
194        * Clear all of this canvases event handlers (the ones installed by RGraph)
195        */
196        RGraph.ClearEventListeners(this.id);
197
198
199        this.diameter    = Math.min(RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom, RGraph.GetWidth(this)) - this.gutterLeft - this.gutterRight;
200        this.radius      = this.Get('chart.radius') ? this.Get('chart.radius') : this.diameter / 2;
201        // this.centerx now defined below
202        this.centery     = ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop;
203        this.subTotal    = 0;
204        this.angles      = [];
205       
206        /**
207        * Alignment (Pie is center aligned by default) Only if centerx is not defined - donut defines the centerx
208        */
209        if (this.Get('chart.align') == 'left') {
210            this.centerx = this.radius + this.gutterLeft;
211       
212        } else if (this.Get('chart.align') == 'right') {
213            this.centerx = RGraph.GetWidth(this) - this.radius - this.gutterRight;
214       
215        } else {
216            this.centerx = RGraph.GetWidth(this) / 2;
217        }
218
219        /**
220        * Draw the shadow if required
221        */
222        if (this.Get('chart.shadow') && 0) {
223       
224            var offsetx = document.all ? this.Get('chart.shadow.offsetx') : 0;
225            var offsety = document.all ? this.Get('chart.shadow.offsety') : 0;
226
227            this.context.beginPath();
228            this.context.fillStyle = this.Get('chart.shadow.color');
229
230            this.context.shadowColor   = this.Get('chart.shadow.color');
231            this.context.shadowBlur    = this.Get('chart.shadow.blur');
232            this.context.shadowOffsetX = this.Get('chart.shadow.offsetx');
233            this.context.shadowOffsetY = this.Get('chart.shadow.offsety');
234           
235            this.context.arc(this.centerx + offsetx, this.centery + offsety, this.radius, 0, 6.28, 0);
236           
237            this.context.fill();
238           
239            // Now turn off the shadow
240            RGraph.NoShadow(this);
241        }
242
243        /**
244        * The total of the array of values
245        */
246        this.total = RGraph.array_sum(this.data);
247
248        for (var i=0,len=this.data.length; i<len; i++) {
249            var angle = (this.data[i] / this.total) * 360;
250   
251            // Draw the segment
252            this.DrawSegment(angle,this.Get('chart.colors')[i],i == (this.data.length - 1), i);
253        }
254
255        RGraph.NoShadow(this);
256
257
258        /**
259        * Redraw the seperating lines
260        */
261        this.DrawBorders();
262
263        /**
264        * Now draw the segments again with shadow turned off. This is always performed,
265        * not just if the shadow is on.
266        */
267        for (var i=0; i<this.angles.length; i++) {
268   
269            this.context.beginPath();
270                this.context.strokeStyle = this.Get('chart.strokestyle');
271                this.context.fillStyle = this.Get('chart.colors')[i];
272                this.context.moveTo(this.angles[i][2], this.angles[i][3]);
273                this.context.arc(this.angles[i][2], this.angles[i][3], this.radius, this.angles[i][0] / 57.3, this.angles[i][1] / 57.3, false);
274                this.context.lineTo(this.angles[i][2], this.angles[i][3]);
275            this.context.closePath();
276            this.context.fill();
277            this.context.stroke();
278        }
279
280        /**
281        * Draw label sticks
282        */
283        if (this.Get('chart.labels.sticks')) {
284            this.DrawSticks();
285           
286            // Redraw the border going around the Pie chart if the stroke style is NOT white
287            if (
288                  this.Get('chart.strokestyle') != 'white'
289               && this.Get('chart.strokestyle') != '#fff'
290               && this.Get('chart.strokestyle') != '#fffffff'
291               && this.Get('chart.strokestyle') != 'rgb(255,255,255)'
292               && this.Get('chart.strokestyle') != 'rgba(255,255,255,0)'
293              ) {
294
295               // Again (?)
296              this.DrawBorders();
297           }
298        }
299
300        /**
301        * Draw the labels
302        */
303        this.DrawLabels();
304
305        /**
306        * Draw the title
307        */
308        if (this.Get('chart.align') == 'left') {
309            var centerx = this.radius + this.Get('chart.gutter.left');
310
311        } else if (this.Get('chart.align') == 'right') {
312            var centerx = RGraph.GetWidth(this) - (this.radius + this.gutterRight);
313
314        } else {
315            var centerx = null;
316        }
317
318        RGraph.DrawTitle(this.canvas, this.Get('chart.title'), (this.canvas.height / 2) - this.radius - 5, centerx, this.Get('chart.text.size') + 2);
319       
320       
321        /**
322        * Setup the context menu if required
323        */
324        if (this.Get('chart.contextmenu')) {
325            RGraph.ShowContext(this);
326        }
327
328        /**
329        * Tooltips
330        */
331        if (this.Get('chart.tooltips').length) {
332
333            /**
334            * Register this object for redrawing
335            */
336            RGraph.Register(this);
337       
338            /**
339            * The onclick event
340            */
341            //this.canvas.onclick = function (e)
342            var canvas_onclick_func = function (e)
343            {
344                RGraph.HideZoomedCanvas();
345
346                e = RGraph.FixEventObject(e);
347
348                var mouseCoords = RGraph.getMouseXY(e);
349
350                var canvas  = e.target;
351                var context = canvas.getContext('2d');
352                var obj     = e.target.__object__;
353
354
355
356                /**
357                * If it's actually a donut make sure the hyp is bigger
358                * than the size of the hole in the middle
359                */
360                if (obj.Get('chart.variant') == 'donut' && Math.abs(hyp) < (obj.radius / 2)) {
361                    return;
362                }
363
364                /**
365                * The angles for each segment are stored in "angles",
366                * so go through that checking if the mouse position corresponds
367                */
368                var isDonut = obj.Get('chart.variant') == 'donut';
369                var hStyle  = obj.Get('chart.highlight.style');
370                var segment = obj.getSegment(e);
371
372                if (segment) {
373
374                    var x     = mouseCoords[0] - segment[0];
375                    var y     = mouseCoords[1] - segment[1];
376                    var theta = Math.atan(y / x); // RADIANS
377                    var hyp   = y / Math.sin(theta);
378
379
380                    if (RGraph.Registry.Get('chart.tooltip') && segment[5] == RGraph.Registry.Get('chart.tooltip').__index__) {
381                        return;
382                    } else {
383                        RGraph.Redraw();
384                    }
385
386
387                    if (isDonut || hStyle == '2d') {
388                       
389                        context.beginPath();
390
391                        context.strokeStyle = obj.Get('chart.highlight.style.2d.stroke');
392                        context.fillStyle   = obj.Get('chart.highlight.style.2d.fill');
393
394                        //context.moveTo(obj.centerx, obj.centery);
395
396                        context.moveTo(segment[0], segment[1]);
397                        context.arc(segment[0], segment[1], segment[2], RGraph.degrees2Radians(obj.angles[segment[5]][0]), RGraph.degrees2Radians(obj.angles[segment[5]][1]), 0);
398                        context.lineTo(segment[0], segment[1]);
399                        context.closePath();
400                       
401                        context.stroke();
402                        context.fill();
403                       
404                        //Removed 7th December 2010
405                        //context.stroke();
406
407                    } else if (hStyle == 'explode') {
408
409                        var exploded = [];
410
411                        exploded[segment[5]] = 0;
412
413                        RGraph.Registry.Set('chart.pie.exploded', obj);
414                       
415                        setTimeout(function () {var pie = RGraph.Registry.Get('chart.pie.exploded'); pie.Set('chart.exploded', exploded);RGraph.Clear(pie.canvas);pie.Draw(); exploded[segment[5]] += 7;}, 25);
416                        setTimeout(function () {var pie = RGraph.Registry.Get('chart.pie.exploded'); pie.Set('chart.exploded', exploded);RGraph.Clear(pie.canvas);pie.Draw(); exploded[segment[5]] += 7;}, 50);
417                        setTimeout(function () {var pie = RGraph.Registry.Get('chart.pie.exploded'); pie.Set('chart.exploded', exploded);RGraph.Clear(pie.canvas);pie.Draw(); exploded[segment[5]] += 7;}, 75);
418                        setTimeout(function () {var pie = RGraph.Registry.Get('chart.pie.exploded'); pie.Set('chart.exploded', exploded);RGraph.Clear(pie.canvas);pie.Draw(); exploded[segment[5]] += 7;}, 100);
419                        setTimeout(function () {var pie = RGraph.Registry.Get('chart.pie.exploded'); pie.Set('chart.exploded', exploded);RGraph.Clear(pie.canvas);pie.Draw(); exploded[segment[5]] += 7;}, 125);
420                       
421                        setTimeout(function () {RGraph.Registry.Get('chart.pie.exploded').Set('chart.exploded', []);}, 150);
422
423                    } else {
424
425                        context.lineWidth = 2;
426
427                        /**
428                        * Draw a white segment where the one that has been clicked on was
429                        */
430                        context.fillStyle = 'white';
431                        context.strokeStyle = 'white';
432                        context.beginPath();
433                        context.moveTo(segment[0], segment[1]);
434                        context.arc(segment[0], segment[1], segment[2], obj.angles[segment[5]][0] / 57.3, obj.angles[segment[5]][1] / 57.3, 0);
435                        context.stroke();
436                        context.fill();
437
438                        context.lineWidth = 1;
439
440                        context.shadowColor   = '#666';
441                        context.shadowBlur    = 3;
442                        context.shadowOffsetX = 3;
443                        context.shadowOffsetY = 3;
444
445                        // Draw the new segment
446                        context.beginPath();
447                            context.fillStyle   = obj.Get('chart.colors')[segment[5]];
448                            context.strokeStyle = obj.Get('chart.strokestyle');
449                            context.moveTo(segment[0] - 3, segment[1] - 3);
450                            context.arc(segment[0] - 3, segment[1] - 3, segment[2], RGraph.degrees2Radians(obj.angles[segment[5]][0]), RGraph.degrees2Radians(obj.angles[segment[5]][1]), 0);
451                            context.lineTo(segment[0] - 3, segment[1] - 3);
452                        context.closePath();
453                       
454                        context.stroke();
455                        context.fill();
456                       
457                        // Turn off the shadow
458                        RGraph.NoShadow(obj);
459                       
460                        /**
461                        * If a border is defined, redraw that
462                        */
463                        if (obj.Get('chart.border')) {
464                            context.beginPath();
465                            context.strokeStyle = obj.Get('chart.border.color');
466                            context.lineWidth = 5;
467                            context.arc(segment[0] - 3, segment[1] - 3, obj.radius - 2, RGraph.degrees2Radians(obj.angles[i][0]), RGraph.degrees2Radians(obj.angles[i][1]), 0);
468                            context.stroke();
469                        }
470                    }
471                       
472                    /**
473                    * If a tooltip is defined, show it
474                    */
475
476                    /**
477                    * Get the tooltip text
478                    */
479                    if (typeof(obj.Get('chart.tooltips')) == 'function') {
480                        var text = String(obj.Get('chart.tooltips')(segment[5]));
481
482                    } else if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(obj.Get('chart.tooltips')[segment[5]]) == 'function') {
483                        var text = String(obj.Get('chart.tooltips')[segment[5]](segment[5]));
484                   
485                    } else if (typeof(obj.Get('chart.tooltips')) == 'object') {
486                        var text = String(obj.Get('chart.tooltips')[segment[5]]);
487
488                    } else {
489                        var text = '';
490                    }
491
492                    if (text) {
493                        RGraph.Tooltip(canvas, text, e.pageX, e.pageY, segment[5]);
494                    }
495
496                    /**
497                    * Need to redraw the key?
498                    */
499                    if (obj.Get('chart.key') && obj.Get('chart.key').length && obj.Get('chart.key.position') == 'graph') {
500                        RGraph.DrawKey(obj, obj.Get('chart.key'), obj.Get('chart.colors'));
501                    }
502
503                    e.stopPropagation();
504
505                    return;
506                } else if (obj.Get('chart.tooltips.event') == 'onclick') {
507                    RGraph.Redraw();
508                }
509            }
510            var event_name = this.Get('chart.tooltips.event') == 'onmousemove' ? 'mousemove' : 'click';
511
512            this.canvas.addEventListener(event_name, canvas_onclick_func, false);
513            RGraph.AddEventListener(this.id, event_name, canvas_onclick_func);
514
515
516
517
518
519
520            /**
521            * The onmousemove event for changing the cursor
522            */
523            //this.canvas.onmousemove = function (e)
524            var canvas_onmousemove_func = function (e)
525            {
526                RGraph.HideZoomedCanvas();
527
528                e = RGraph.FixEventObject(e);
529               
530                var obj     = e.target.__object__;
531                var segment = obj.getSegment(e);
532
533                if (segment) {
534                    e.target.style.cursor = 'pointer';
535
536                    return;
537                }
538
539                /**
540                * Put the cursor back to null
541                */
542                e.target.style.cursor = 'default';
543            }
544            this.canvas.addEventListener('mousemove', canvas_onmousemove_func, false);
545            RGraph.AddEventListener(this.id, 'mousemove', canvas_onmousemove_func);
546
547
548
549
550
551
552
553
554
555            /**
556            * The window onclick function
557            */
558            var window_onclick_func = function (e)
559            {
560                RGraph.HideZoomedCanvas();
561
562                e = RGraph.FixEventObject(e);
563
564                RGraph.Redraw();
565
566                /**
567                * Put the cursor back to null
568                */
569                e.target.style.cursor = 'default';
570            }
571            window.addEventListener('click', window_onclick_func, false);
572            RGraph.AddEventListener('window_' + this.id, 'click', window_onclick_func);
573        }
574
575
576        /**
577        * If a border is pecified, draw it
578        */
579        if (this.Get('chart.border')) {
580            this.context.beginPath();
581            this.context.lineWidth = 5;
582            this.context.strokeStyle = this.Get('chart.border.color');
583
584            this.context.arc(this.centerx,
585                             this.centery,
586                             this.radius - 2,
587                             0,
588                             6.28,
589                             0);
590
591            this.context.stroke();
592        }
593       
594        /**
595        * Draw the kay if desired
596        */
597        if (this.Get('chart.key') != null) {
598            //this.Set('chart.key.position', 'graph');
599            RGraph.DrawKey(this, this.Get('chart.key'), this.Get('chart.colors'));
600        }
601
602
603        /**
604        * If this is actually a donut, draw a big circle in the middle
605        */
606        if (this.Get('chart.variant') == 'donut') {
607            this.context.beginPath();
608            this.context.strokeStyle = this.Get('chart.strokestyle');
609            this.context.fillStyle   = this.Get('chart.variant.donut.color');
610            this.context.arc(this.centerx, this.centery, this.radius / 2, 0, 6.28, 0);
611            this.context.stroke();
612            this.context.fill();
613        }
614       
615        RGraph.NoShadow(this);
616       
617        /**
618        * If the canvas is annotatable, do install the event handlers
619        */
620        if (this.Get('chart.annotatable')) {
621            RGraph.Annotate(this);
622        }
623       
624        /**
625        * This bit shows the mini zoom window if requested
626        */
627        if (this.Get('chart.zoom.mode') == 'thumbnail' || this.Get('chart.zoom.mode') == 'area') {
628            RGraph.ShowZoomWindow(this);
629        }
630
631       
632        /**
633        * This function enables resizing
634        */
635        if (this.Get('chart.resizable')) {
636            RGraph.AllowResizing(this);
637        }
638       
639        /**
640        * Fire the RGraph ondraw event
641        */
642        RGraph.FireCustomEvent(this, 'ondraw');
643    }
644
645
646    /**
647    * Draws a single segment of the pie chart
648    *
649    * @param int degrees The number of degrees for this segment
650    */
651    RGraph.Pie.prototype.DrawSegment = function (degrees, color, last, index)
652    {
653        var context  = this.context;
654        var canvas   = this.canvas;
655        var subTotal = this.subTotal;
656
657        context.beginPath();
658
659            context.fillStyle   = color;
660            context.strokeStyle = this.Get('chart.strokestyle');
661            context.lineWidth   = 0;
662           
663            if (this.Get('chart.shadow')) {
664                RGraph.SetShadow(this, this.Get('chart.shadow.color'),this.Get('chart.shadow.offsetx'), this.Get('chart.shadow.offsety'), this.Get('chart.shadow.blur'));
665            }
666
667            /**
668            * Exploded segments
669            */
670            if ( (typeof(this.Get('chart.exploded')) == 'object' && this.Get('chart.exploded')[index] > 0)) {
671                var explosion = this.Get('chart.exploded')[index];
672                var x         = 0;
673                var y         = 0;
674                var h         = explosion;
675                var t         = (subTotal + (degrees / 2)) / (360/6.2830);
676                var x         = (Math.cos(t) * explosion);
677                var y         = (Math.sin(t) * explosion);
678           
679                this.context.moveTo(this.centerx + x, this.centery + y);
680            } else {
681                var x = 0;
682                var y = 0;
683            }
684
685            context.arc(this.centerx + x,
686                        this.centery + y,
687                        this.radius,
688                        subTotal / 57.3,
689                        (last ? 360 : subTotal + degrees) / 57.3,
690                        0);
691   
692            context.lineTo(this.centerx + x, this.centery + y);
693           
694            // Keep hold of the angles
695            this.angles.push([subTotal, subTotal + degrees, this.centerx + x, this.centery + y])
696        this.context.closePath();
697       
698
699       
700        //this.context.stroke();
701        this.context.fill();
702
703        /**
704        * Calculate the segment angle
705        */
706        this.Get('chart.segments').push([subTotal, subTotal + degrees]);
707        this.subTotal += degrees;
708    }
709
710    /**
711    * Draws the graphs labels
712    */
713    RGraph.Pie.prototype.DrawLabels = function ()
714    {
715        var hAlignment = 'left';
716        var vAlignment = 'center';
717        var labels     = this.Get('chart.labels');
718        var context    = this.context;
719
720        /**
721        * Turn the shadow off
722        */
723        RGraph.NoShadow(this);
724       
725        context.fillStyle = 'black';
726        context.beginPath();
727
728        /**
729        * Draw the key (ie. the labels)
730        */
731        if (labels && labels.length) {
732
733            var text_size = this.Get('chart.text.size');
734
735            for (i=0; i<labels.length; ++i) {
736           
737                /**
738                * T|his ensures that if we're given too many labels, that we don't get an error
739                */
740                if (typeof(this.Get('chart.segments')[i]) == 'undefined') {
741                    continue;
742                }
743
744                // Move to the centre
745                context.moveTo(this.centerx,this.centery);
746               
747                var a = this.Get('chart.segments')[i][0] + ((this.Get('chart.segments')[i][1] - this.Get('chart.segments')[i][0]) / 2);
748
749                /**
750                * Alignment
751                */
752                if (a < 90) {
753                    hAlignment = 'left';
754                    vAlignment = 'center';
755                } else if (a < 180) {
756                    hAlignment = 'right';
757                    vAlignment = 'center';
758                } else if (a < 270) {
759                    hAlignment = 'right';
760                    vAlignment = 'center';
761                } else if (a < 360) {
762                    hAlignment = 'left';
763                    vAlignment = 'center';
764                }
765
766
767                /**
768                * Handle the additional "explosion" offset
769                */
770                if (typeof(this.Get('chart.exploded')) == 'object' && this.Get('chart.exploded')[i]) {
771
772                    var t = ((this.angles[i][1] - this.angles[i][0]) / 2) / (360/6.2830);
773                    var seperation = this.Get('chart.exploded')[i];
774                    var angle = ((this.angles[i][1] - this.angles[i][0]) / 2) + this.angles[i][0];
775
776                    // Adjust the angles
777                    var explosion_offsetx = (Math.cos(angle / 57.29) * seperation);
778                    var explosion_offsety = (Math.sin(angle / 57.29) * seperation);
779                } else {
780                    var explosion_offsetx = 0;
781                    var explosion_offsety = 0;
782                }
783
784                context.fillStyle = this.Get('chart.text.color');
785
786                RGraph.Text(context,
787                            this.Get('chart.text.font'),
788                            text_size,
789                            this.centerx + explosion_offsetx + ((this.radius + 10)* Math.cos(a / 57.3)) + (this.Get('chart.labels.sticks') ? (a < 90 || a > 270 ? 2 : -2) : 0),
790                            this.centery + explosion_offsety + (((this.radius + 10) * Math.sin(a / 57.3))),
791                            labels[i],
792                            vAlignment,
793                            hAlignment);
794            }
795           
796            context.fill();
797        }
798    }
799
800
801    /**
802    * This function draws the pie chart sticks (for the labels)
803    */
804    RGraph.Pie.prototype.DrawSticks = function ()
805    {
806        var context  = this.context;
807        var segments = this.Get('chart.segments');
808        var offset   = this.Get('chart.linewidth') / 2;
809        var exploded = this.Get('chart.exploded');
810        var sticks   = this.Get('chart.labels.sticks');
811
812        for (var i=0; i<segments.length; ++i) {
813       
814            // This allows the chart.labels.sticks to be an array as well as a boolean
815            if (typeof(sticks) == 'object' && !sticks[i]) {
816                continue;
817            }
818
819            var degrees = segments[i][1] - segments[i][0];
820
821            context.beginPath();
822            context.strokeStyle = this.Get('chart.labels.sticks.color');
823            context.lineWidth   = 1;
824
825            var midpoint = (segments[i][0] + (degrees / 2)) / 57.3;
826
827            if (exploded && exploded[i]) {
828                var extra = exploded[i];
829            } else {
830                var extra = 0;
831            }
832           
833            context.lineJoin = 'round';
834            context.lineWidth = 1;
835
836            context.arc(this.centerx,
837                        this.centery,
838                        this.radius + 7 + extra,
839                        midpoint,
840                        midpoint + 0.01,
841                        0);
842           
843            context.arc(this.centerx,
844                        this.centery,
845                        this.radius - offset + extra,
846                        midpoint,
847                        midpoint + 0.01,
848                        0);
849
850            context.stroke();
851        }
852    }
853
854
855    /**
856    * The (now Pie chart specific) getSegment function
857    *
858    * @param object e The event object
859    */
860    RGraph.Pie.prototype.getSegment = function (e)
861    {
862        RGraph.FixEventObject(e);
863
864        // The optional arg provides a way of allowing some accuracy (pixels)
865        var accuracy = arguments[1] ? arguments[1] : 0;
866
867        var obj         = e.target.__object__;
868        var canvas      = obj.canvas;
869        var context     = obj.context;
870        var mouseCoords = RGraph.getMouseXY(e);
871        var r           = obj.radius;
872        var angles      = obj.angles;
873        var ret         = [];
874
875        for (var i=0; i<angles.length; ++i) {
876
877            var x     = mouseCoords[0] - angles[i][2];
878            var y     = mouseCoords[1] - angles[i][3];
879            var theta = Math.atan(y / x); // RADIANS
880            var hyp   = y / Math.sin(theta);
881            var hyp   = (hyp < 0) ? hyp + accuracy : hyp - accuracy;
882            // Put theta in DEGREES
883            theta *= 57.3
884
885            /**
886            * Account for the correct quadrant
887            */
888            if (x < 0 && y >= 0) {
889                theta += 180;
890            } else if (x < 0 && y < 0) {
891                theta += 180;
892            } else if (x > 0 && y < 0) {
893                theta += 360;
894            }
895           
896            if (theta > 360) {
897                theta -= 360;
898            }
899
900            if (theta >= angles[i][0] && theta < angles[i][1]) {
901
902                hyp = Math.abs(hyp);
903
904                if (!hyp || (obj.radius && hyp > obj.radius) ) {
905                    return null;
906                }
907
908                if (obj.type == 'pie' && obj.Get('chart.variant') == 'donut' && (hyp > obj.radius || hyp < (obj.radius / 2) ) ) {
909                    return null;
910                }
911
912                ret[0] = angles[i][2];
913                ret[1] = angles[i][3];
914                ret[2] = (obj.type == 'rose') ? angles[i][2] : obj.radius;
915                ret[3] = angles[i][0];
916                ret[4] = angles[i][1];
917                ret[5] = i;
918
919
920               
921                if (ret[3] < 0) ret[3] += 360;
922                if (ret[4] > 360) ret[4] -= 360;
923
924                return ret;
925            }
926        }
927       
928        return null;
929    }
930
931
932    RGraph.Pie.prototype.DrawBorders = function ()
933    {
934        if (this.Get('chart.linewidth') > 0) {
935
936            this.context.lineWidth = this.Get('chart.linewidth');
937            this.context.strokeStyle = this.Get('chart.strokestyle');
938
939            for (var i=0,len=this.angles.length; i<len; ++i) {
940                this.context.beginPath();
941                    this.context.moveTo(this.angles[i][2], this.angles[i][3]);
942                    this.context.arc(this.angles[i][2], this.angles[i][3], this.radius, this.angles[i][0] / 57.3, (this.angles[i][0] + 0.01) / 57.3, 0);
943                    this.context.arc(this.angles[i][2], this.angles[i][3], this.radius, this.angles[i][0] / 57.3, (this.angles[i][1]) / 57.3, 0);
944                this.context.closePath();
945               
946                this.context.stroke();
947            }
948        }
949    }
Note: See TracBrowser for help on using the repository browser.