rgraph-rails 5.00 → 6.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/publish-geml.yaml +46 -0
  3. data/.gitignore +1 -0
  4. data/README.md +4 -5
  5. data/lib/rgraph-rails/version.rb +1 -1
  6. data/rgraph-rails.gemspec +4 -4
  7. data/vendor/assets/javascripts/RGraph.activity.js +1691 -0
  8. data/vendor/assets/javascripts/RGraph.bar.js +4253 -236
  9. data/vendor/assets/javascripts/RGraph.bipolar.js +3958 -162
  10. data/vendor/assets/javascripts/RGraph.common.annotate.js +414 -35
  11. data/vendor/assets/javascripts/RGraph.common.context.js +635 -30
  12. data/vendor/assets/javascripts/RGraph.common.core.js +10485 -419
  13. data/vendor/assets/javascripts/RGraph.common.csv.js +508 -27
  14. data/vendor/assets/javascripts/RGraph.common.dynamic.js +1693 -90
  15. data/vendor/assets/javascripts/RGraph.common.effects.js +1629 -89
  16. data/vendor/assets/javascripts/RGraph.common.key.js +1003 -53
  17. data/vendor/assets/javascripts/RGraph.common.moment.js +5670 -0
  18. data/vendor/assets/javascripts/RGraph.common.sheets.js +541 -31
  19. data/vendor/assets/javascripts/RGraph.common.sheets.php +351 -0
  20. data/vendor/assets/javascripts/RGraph.common.starburst.js +382 -0
  21. data/vendor/assets/javascripts/RGraph.common.table.js +386 -0
  22. data/vendor/assets/javascripts/RGraph.common.tooltips.js +1433 -32
  23. data/vendor/assets/javascripts/RGraph.drawing.background.js +660 -35
  24. data/vendor/assets/javascripts/RGraph.drawing.circle.js +618 -34
  25. data/vendor/assets/javascripts/RGraph.drawing.image.js +857 -52
  26. data/vendor/assets/javascripts/RGraph.drawing.line.js +712 -0
  27. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +760 -38
  28. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +740 -37
  29. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +573 -36
  30. data/vendor/assets/javascripts/RGraph.drawing.poly.js +667 -36
  31. data/vendor/assets/javascripts/RGraph.drawing.rect.js +638 -34
  32. data/vendor/assets/javascripts/RGraph.drawing.text.js +672 -37
  33. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +653 -52
  34. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +714 -51
  35. data/vendor/assets/javascripts/RGraph.fuel.js +1149 -59
  36. data/vendor/assets/javascripts/RGraph.funnel.js +1277 -56
  37. data/vendor/assets/javascripts/RGraph.gantt.js +1646 -82
  38. data/vendor/assets/javascripts/RGraph.gauge.js +1773 -89
  39. data/vendor/assets/javascripts/RGraph.hbar.js +3869 -159
  40. data/vendor/assets/javascripts/RGraph.horseshoe.js +970 -0
  41. data/vendor/assets/javascripts/RGraph.hprogress.js +1829 -81
  42. data/vendor/assets/javascripts/RGraph.line.js +5293 -244
  43. data/vendor/assets/javascripts/RGraph.meter.js +1570 -77
  44. data/vendor/assets/javascripts/RGraph.modaldialog.js +300 -19
  45. data/vendor/assets/javascripts/RGraph.odo.js +1553 -68
  46. data/vendor/assets/javascripts/RGraph.pie.js +3273 -129
  47. data/vendor/assets/javascripts/RGraph.radar.js +2333 -108
  48. data/vendor/assets/javascripts/RGraph.rose.js +2685 -114
  49. data/vendor/assets/javascripts/RGraph.rscatter.js +1920 -80
  50. data/vendor/assets/javascripts/RGraph.scatter.js +4215 -171
  51. data/vendor/assets/javascripts/RGraph.segmented.js +1006 -0
  52. data/vendor/assets/javascripts/RGraph.semicircularprogress.js +1980 -59
  53. data/vendor/assets/javascripts/RGraph.svg.activity.js +1696 -0
  54. data/vendor/assets/javascripts/RGraph.svg.bar.js +2575 -77
  55. data/vendor/assets/javascripts/RGraph.svg.bipolar.js +3533 -106
  56. data/vendor/assets/javascripts/RGraph.svg.common.ajax.js +240 -21
  57. data/vendor/assets/javascripts/RGraph.svg.common.core.js +7105 -299
  58. data/vendor/assets/javascripts/RGraph.svg.common.csv.js +408 -28
  59. data/vendor/assets/javascripts/RGraph.svg.common.fx.js +1291 -68
  60. data/vendor/assets/javascripts/RGraph.svg.common.key.js +451 -20
  61. data/vendor/assets/javascripts/RGraph.svg.common.sheets.js +543 -31
  62. data/vendor/assets/javascripts/RGraph.svg.common.table.js +391 -0
  63. data/vendor/assets/javascripts/RGraph.svg.common.tooltips.js +1072 -23
  64. data/vendor/assets/javascripts/RGraph.svg.funnel.js +1151 -32
  65. data/vendor/assets/javascripts/RGraph.svg.gauge.js +1429 -34
  66. data/vendor/assets/javascripts/RGraph.svg.hbar.js +2692 -65
  67. data/vendor/assets/javascripts/RGraph.svg.horseshoe.js +969 -0
  68. data/vendor/assets/javascripts/RGraph.svg.line.js +2855 -86
  69. data/vendor/assets/javascripts/RGraph.svg.pie.js +1630 -58
  70. data/vendor/assets/javascripts/RGraph.svg.radar.js +1772 -58
  71. data/vendor/assets/javascripts/RGraph.svg.rose.js +2419 -83
  72. data/vendor/assets/javascripts/RGraph.svg.scatter.js +2280 -65
  73. data/vendor/assets/javascripts/RGraph.svg.segmented.js +930 -0
  74. data/vendor/assets/javascripts/RGraph.svg.semicircularprogress.js +1612 -29
  75. data/vendor/assets/javascripts/RGraph.svg.waterfall.js +1525 -50
  76. data/vendor/assets/javascripts/RGraph.thermometer.js +1411 -64
  77. data/vendor/assets/javascripts/RGraph.vprogress.js +1915 -81
  78. data/vendor/assets/javascripts/RGraph.waterfall.js +1896 -89
  79. data/vendor/assets/javascripts/financial-data.js +1067 -0
  80. metadata +37 -16
  81. data/.travis.yml +0 -11
  82. data/vendor/assets/javascripts/RGraph.common.deprecated.js +0 -35
  83. data/vendor/assets/javascripts/RGraph.common.resizing.js +0 -38
  84. data/vendor/assets/javascripts/RGraph.common.zoom.js +0 -15
  85. data/vendor/assets/javascripts/RGraph.cornergauge.js +0 -71
@@ -1,130 +1,3274 @@
1
+ 'version:2023-09-16 (6.14)';
2
+ //
3
+ // o--------------------------------------------------------------------------------o
4
+ // | This file is part of the RGraph package - you can learn more at: |
5
+ // | |
6
+ // | https://www.rgraph.net |
7
+ // | |
8
+ // | RGraph is licensed under the Open Source MIT license. That means that it's |
9
+ // | totally free to use and there are no restrictions on what you can do with it! |
10
+ // o--------------------------------------------------------------------------------o
1
11
 
2
- RGraph=window.RGraph||{isRGraph:true};RGraph.Pie=function(conf)
3
- {if(typeof conf==='object'&&typeof conf.data==='object'&&typeof conf.id==='string'){var id=conf.id,canvas=document.getElementById(id),data=conf.data,parseConfObjectForOptions=true;}else{var id=conf,canvas=document.getElementById(id),data=arguments[1];}
4
- this.id=id;this.canvas=canvas;this.context=this.canvas.getContext?this.canvas.getContext("2d",{alpha:(typeof id==='object'&&id.alpha===false)?false:true}):null;this.canvas.__object__=this;this.total=0;this.subTotal=0;this.angles=[];this.data=data;this.properties=[];this.type='pie';this.isRGraph=true;this.coords=[];this.coords.key=[];this.coordsSticks=[];this.coordsText=[];this.uid=RGraph.CreateUID();this.canvas.uid=this.canvas.uid?this.canvas.uid:RGraph.CreateUID();this.colorsParsed=false;this.original_colors=[];this.firstDraw=true;this.exploding=null;this.propertyNameAliases={};for(var i=0;i<this.data.length;++i){if(typeof this.data[i]==='string'){this.data[i]=parseFloat(this.data[i]);}}
5
- this.properties={'chart.centerx.adjust':0,'chart.centery.adjust':0,'chart.colors':['red','#ccc','#cfc','blue','pink','yellow','black','orange','cyan','purple','#78CAEA','#E284E9','white','blue','#9E7BF6'],'chart.colors.stroke':'white','chart.linewidth':3,'chart.labels':[],'chart.labels.font':null,'chart.labels.size':null,'chart.labels.color':null,'chart.labels.bold':null,'chart.labels.italic':null,'chart.labels.sticks':false,'chart.labels.sticks.length':7,'chart.labels.sticks.colors':null,'chart.labels.sticks.linewidth':1,'chart.labels.sticks.hlength':5,'chart.labels.list':true,'chart.labels.ingraph':null,'chart.labels.ingraph.color':null,'chart.labels.ingraph.font':null,'chart.labels.ingraph.size':null,'chart.labels.ingraph.bold':null,'chart.labels.ingraph.italic':null,'chart.labels.ingraph.bounding':true,'chart.labels.ingraph.bounding.fill':'rgba(255,255,255,0.85)','chart.labels.ingraph.bounding.stroke':'rgba(0,0,0,0)','chart.labels.ingraph.specific':null,'chart.labels.ingraph.units.pre':'','chart.labels.ingraph.units.post':'','chart.labels.ingraph.point':'.','chart.labels.ingraph.thousand':',','chart.labels.ingraph.decimals':0,'chart.labels.ingraph.radius':null,'chart.labels.center':null,'chart.labels.center.size':26,'chart.labels.center.font':null,'chart.labels.center.color':null,'chart.labels.center.italic':null,'chart.labels.center.bold':null,'chart.margin.left':25,'chart.margin.right':25,'chart.margin.top':25,'chart.margin.bottom':25,'chart.title':'','chart.title.background':null,'chart.title.hpos':null,'chart.title.vpos':0.5,'chart.title.bold':null,'chart.title.font':null,'chart.title.size':null,'chart.title.color':null,'chart.title.italic':null,'chart.title.x':null,'chart.title.y':null,'chart.title.halign':null,'chart.title.valign':null,'chart.shadow':true,'chart.shadow.color':'#aaa','chart.shadow.offsetx':0,'chart.shadow.offsety':0,'chart.shadow.blur':15,'chart.text.bold':false,'chart.text.italic':false,'chart.text.size':12,'chart.text.color':'black','chart.text.font':'Arial, Verdana, sans-serif','chart.text.accessible':true,'chart.text.accessible.overflow':'visible','chart.text.accessible.pointerevents':false,'chart.contextmenu':null,'chart.tooltips':null,'chart.tooltips.event':'onclick','chart.tooltips.effect':'fade','chart.tooltips.css.class':'RGraph_tooltip','chart.tooltips.highlight':true,'chart.highlight.style':'2d','chart.highlight.style.twod.fill':'rgba(255,255,255,0.7)','chart.highlight.style.twod.stroke':'rgba(255,255,255,0.7)','chart.highlight.style.outline.width':null,'chart.centerx':null,'chart.centery':null,'chart.radius':null,'chart.border':false,'chart.border.color':'rgba(255,255,255,0.5)','chart.key':null,'chart.key.background':'white','chart.key.position':'graph','chart.key.halign':'right','chart.key.shadow':false,'chart.key.shadow.color':'#666','chart.key.shadow.blur':3,'chart.key.shadow.offsetx':2,'chart.key.shadow.offsety':2,'chart.key.position.gutter.boxed':false,'chart.key.position.x':null,'chart.key.position.y':null,'chart.key.color.shape':'square','chart.key.rounded':true,'chart.key.linewidth':1,'chart.key.colors':null,'chart.key.interactive':false,'chart.key.interactive.highlight.chart.stroke':'black','chart.key.interactive.highlight.chart.fill':'rgba(255,255,255,0.7)','chart.key.interactive.highlight.label':'rgba(255,0,0,0.2)','chart.key.labels.color':null,'chart.key.labels.font':null,'chart.key.labels.size':null,'chart.key.labels.bold':null,'chart.key.labels.italic':null,'chart.key.labels.offsetx':0,'chart.key.labels.offsety':0,'chart.annotatable':false,'chart.annotatable.color':'black','chart.resizable':false,'chart.resizable.handle.adjust':[0,0],'chart.resizable.handle.background':null,'chart.variant':'pie','chart.variant.donut.width':null,'chart.variant.threed.depth':20,'chart.exploded':[],'chart.effect.roundrobin.multiplier':1,'chart.events':true,'chart.events.click':null,'chart.events.mousemove':null,'chart.centerpin':null,'chart.centerpin.fill':'gray','chart.centerpin.stroke':'white','chart.origin':0-(Math.PI/2),'chart.clearto':'rgba(0,0,0,0)'}
6
- for(var i=0,len=data.length;i<len;i++){this.total+=data[i];this['$'+i]={};}
7
- if(!this.canvas.__rgraph_aa_translated__){this.context.translate(0.5,0.5);this.canvas.__rgraph_aa_translated__=true;}
8
- var RG=RGraph,ca=this.canvas,co=ca.getContext('2d'),prop=this.properties,pa2=RG.path2,win=window,doc=document,ma=Math
9
- if(RG.Effects&&typeof RG.Effects.decorate==='function'){RG.Effects.decorate(this);}
10
- this.set=this.Set=function(name)
11
- {var value=typeof arguments[1]==='undefined'?null:arguments[1];if(arguments.length===1&&typeof name==='object'){RG.parseObjectStyleConfig(this,name);return this;}
12
- if(name.substr(0,6)!='chart.'){name='chart.'+name;}
13
- while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
14
- prop[name]=value;return this;};this.get=this.Get=function(name)
15
- {if(name.substr(0,6)!='chart.'){name='chart.'+name;}
16
- while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
17
- if(name=='chart.highlight.style.twod.color'){name='chart.highlight.style.twod.fill';}
18
- return prop[name];};this.draw=this.Draw=function()
19
- {RG.fireCustomEvent(this,'onbeforedraw');this.marginLeft=prop['chart.margin.left'];this.marginRight=prop['chart.margin.right'];this.marginTop=prop['chart.margin.top'];this.marginBottom=prop['chart.margin.bottom'];this.radius=this.getRadius();this.centerx=(this.graph.width/2)+this.marginLeft+prop['chart.centerx.adjust'];this.centery=(this.graph.height/2)+this.marginTop+prop['chart.centery.adjust'];this.subTotal=this.properties['chart.origin'];this.angles=[];this.coordsText=[];if(typeof prop['chart.radius']==='number')this.radius=prop['chart.radius'];if(typeof prop['chart.centerx']==='number')this.centerx=prop['chart.centerx'];if(typeof prop['chart.centery']==='number')this.centery=prop['chart.centery'];if(this.radius<=0){return;}
20
- if(!this.colorsParsed){this.parseColors();this.colorsParsed=true;}
21
- if(prop['chart.variant'].indexOf('3d')>0){return this.draw3d();}
22
- RG.drawTitle(this,prop['chart.title'],(ca.height/2)-this.radius-5,this.centerx,prop['chart.title.size']?prop['chart.title.size']:prop['chart.text.size']);this.total=RG.arraySum(this.data);var tot=this.total;var data=this.data;for(var i=0,len=this.data.length;i<len;i++){var angle=((data[i]/tot)*RG.TWOPI);this.drawSegment(angle,prop['chart.colors'][i],i==(len-1),i);}
23
- RG.noShadow(this);if(prop['chart.linewidth']>0){this.drawBorders();}
24
- var len=this.angles.length;var r=this.radius;for(var action=0;action<2;action+=1){for(var i=0;i<len;i++){co.beginPath();var segment=this.angles[i];if(action===1){co.strokeStyle=typeof(prop['chart.colors.stroke'])=='object'?prop['chart.colors.stroke'][i]:prop['chart.colors.stroke'];}
25
- prop['chart.colors'][i]?co.fillStyle=prop['chart.colors'][i]:null;co.lineJoin='round';co.arc(segment[2],segment[3],r,(segment[0]),(segment[1]),false);if(prop['chart.variant']=='donut'){co.arc(segment[2],segment[3],typeof(prop['chart.variant.donut.width'])=='number'?r-prop['chart.variant.donut.width']:r/2,(segment[1]),(segment[0]),true);}else{co.lineTo(segment[2],segment[3]);}
26
- co.closePath();action===0?co.fill():co.stroke();}}
27
- if(prop['chart.labels.sticks']){this.DrawSticks();var strokeStyle=prop['chart.colors.stroke'];}
28
- if(prop['chart.labels']){this.drawLabels();}
29
- if(prop['chart.centerpin']){this.drawCenterpin();}
30
- if(prop['chart.labels.ingraph']){this.drawInGraphLabels();}
31
- if(typeof prop['chart.labels.center']==='string'){this.drawCenterLabel(prop['chart.labels.center']);}
32
- if(prop['chart.contextmenu']){RG.showContext(this);}
33
- if(prop['chart.border']){co.beginPath();co.lineWidth=5;co.strokeStyle=prop['chart.border.color'];co.arc(this.centerx,this.centery,this.radius-2,0,RG.TWOPI,0);co.stroke();}
34
- if(prop['chart.key']&&prop['chart.key'].length){RG.drawKey(this,prop['chart.key'],prop['chart.colors']);}
35
- RG.noShadow(this);if(prop['chart.resizable']){RG.allowResizing(this);}
36
- if(prop['chart.events']==true){RG.installEventListeners(this);}
37
- if(this.firstDraw){this.firstDraw=false;RG.fireCustomEvent(this,'onfirstdraw');this.firstDrawFunc();}
38
- RG.fireCustomEvent(this,'ondraw');return this;};this.exec=function(func)
39
- {func(this);return this;};this.drawSegment=this.DrawSegment=function(radians,color,last,index)
40
- {var subTotal=this.subTotal;radians=radians*prop['chart.effect.roundrobin.multiplier'];co.beginPath();color?co.fillStyle=color:null;co.strokeStyle=prop['chart.colors.stroke'];co.lineWidth=0;if(prop['chart.shadow']){RG.setShadow(this,prop['chart.shadow.color'],prop['chart.shadow.offsetx'],prop['chart.shadow.offsety'],prop['chart.shadow.blur']);}
41
- if((typeof(prop['chart.exploded'])=='object'&&prop['chart.exploded'][index]>0)||typeof(prop['chart.exploded'])=='number'){var explosion=typeof(prop['chart.exploded'])=='number'?prop['chart.exploded']:prop['chart.exploded'][index];var x=0;var y=0;var h=explosion;var t=subTotal+(radians/2);var x=(Math.cos(t)*explosion);var y=(Math.sin(t)*explosion);var r=this.radius;co.moveTo(this.centerx+x,this.centery+y);}else{var x=0;var y=0;var r=this.radius;}
42
- var startAngle=subTotal;var endAngle=((subTotal+radians));co.arc(this.centerx+x,this.centery+y,r,startAngle,endAngle,0);if(prop['chart.variant']=='donut'){co.arc(this.centerx+x,this.centery+y,typeof(prop['chart.variant.donut.width'])=='number'?r-prop['chart.variant.donut.width']:r/2,endAngle,startAngle,true);}else{co.lineTo(this.centerx+x,this.centery+y);}
43
- co.closePath();this.angles.push([subTotal,subTotal+radians,this.centerx+x,this.centery+y]);co.fill();this.subTotal+=radians;};this.drawLabels=this.DrawLabels=function()
44
- {if(prop['chart.labels'].length&&prop['chart.labels.list']){return this.drawLabelsList();}
45
- var hAlignment='left',vAlignment='center',labels=prop['chart.labels'],context=co,font=prop['chart.text.font'],bold=prop['chart.labels.bold'],text_size=prop['chart.text.size'],cx=this.centerx,cy=this.centery,r=this.radius;RG.noShadow(this);co.fillStyle='black';co.beginPath();if(labels&&labels.length){var textConf=RG.getTextConf({object:this,prefix:'chart.labels'});for(i=0;i<this.angles.length;++i){var segment=this.angles[i];if(typeof labels[i]!='string'&&typeof labels[i]!='number'){continue;}
46
- co.moveTo(cx,cy);var a=segment[0]+((segment[1]-segment[0])/2),angle=((segment[1]-segment[0])/2)+segment[0];if(typeof prop['chart.exploded']==='object'&&prop['chart.exploded'][i]||typeof prop['chart.exploded']=='number'){var t=((segment[1]-segment[0])/2),seperation=typeof(prop['chart.exploded'])=='number'?prop['chart.exploded']:prop['chart.exploded'][i];var explosion_offsetx=(Math.cos(angle)*seperation),explosion_offsety=(Math.sin(angle)*seperation);}else{var explosion_offsetx=0,explosion_offsety=0;}
47
- if(prop['chart.labels.sticks']){explosion_offsetx+=(ma.cos(angle)*(typeof prop['chart.labels.sticks.length']==='object'?prop['chart.labels.sticks.length'][i]:prop['chart.labels.sticks.length']));explosion_offsety+=(ma.sin(angle)*(typeof prop['chart.labels.sticks.length']==='object'?prop['chart.labels.sticks.length'][i]:prop['chart.labels.sticks.length']));}
48
- var x=cx+explosion_offsetx+((r+10)*Math.cos(a))+(prop['chart.labels.sticks']?(a<RG.HALFPI||a>(RG.TWOPI+RG.HALFPI)?2:-2):0),y=cy+explosion_offsety+(((r+10)*Math.sin(a)));if(this.coordsSticks&&this.coordsSticks[i]){var x=this.coordsSticks[i][4][0]+(x<cx?-5:5),y=this.coordsSticks[i][4][1];}
49
- vAlignment='center';hAlignment=x<cx?'right':'left';co.fillStyle=prop['chart.text.color'];RG.text2(this,{font:textConf.font,size:textConf.size,color:textConf.color,bold:textConf.bold,italic:textConf.italic,x:x,y:y,text:labels[i],valign:vAlignment,halign:hAlignment,tag:'labels'});}
50
- co.fill();}};this.drawLabelsList=function()
51
- {var segment=this.angles[i],labels=prop['chart.labels'],labels_right=[],labels_left=[],left=[],right=[],centerx=this.centerx,centery=this.centery,radius=this.radius,offset=50
52
- for(var i=0;i<this.angles.length;++i){if(RG.isNull(this.data[i])){continue;}
53
- var angle=this.angles[i][0]+((this.angles[i][1]-this.angles[i][0])/2),endpoint_inner=RG.getRadiusEndPoint(centerx,centery,angle,radius+5),endpoint_outer=RG.getRadiusEndPoint(centerx,centery,angle,radius+30),explosion=[(typeof prop['chart.exploded']==='number'?prop['chart.exploded']:prop['chart.exploded'][i]),(ma.cos(angle)*(typeof prop['chart.exploded']==='number'?prop['chart.exploded']:prop['chart.exploded'][i])),(ma.sin(angle)*(typeof prop['chart.exploded']==='number'?prop['chart.exploded']:prop['chart.exploded'][i]))]
54
- var textConf=RG.getTextConf({object:this,prefix:'chart.labels'});if(angle>(-1*RG.HALFPI)&&angle<RG.HALFPI){labels_right.push([i,angle,labels[i]?labels[i]:'',endpoint_inner,endpoint_outer,textConf.color,RG.arrayClone(explosion)]);}else{labels_left.push([i,angle,labels[i]?labels[i]:'',endpoint_inner,endpoint_outer,textConf.color,RG.arrayClone(explosion)]);}}
55
- var vspace_right=(ca.height-prop['chart.margin.top']-prop['chart.margin.bottom'])/labels_right.length
56
- for(var i=0,y=(prop['chart.margin.top']+(vspace_right/2));i<labels_right.length;y+=vspace_right,i++){if(labels_right[i][2]){var x=this.centerx+this.radius+offset,idx=labels_right[i][0],explosionX=labels_right[i][6][0]?labels_right[i][6][1]:0,explosionY=labels_right[i][6][0]?labels_right[i][6][2]:0
57
- var ret=RG.text2(this,{font:textConf.font,size:textConf.size,color:textConf.color,bold:textConf.bold,italic:textConf.italic,x:x+explosionX,y:y+explosionY,text:labels_right[i][2],valign:'center',halign:'left',tag:'labels',color:labels_right[i][5]});if(ret&&ret.node){ret.node.__index__=labels_right[i][0];}
58
- pa2(co,'lc round lw % b m % % qc % % % % s %',prop['chart.labels.sticks.linewidth'],labels_right[i][3][0]+explosionX,labels_right[i][3][1]+explosionY,labels_right[i][4][0]+explosionX,labels_right[i][4][1]+explosionY,ret.x-5,ret.y+(ret.height/2),labels_right[i][5]);pa2(co,'b a % % 2 0 6.2830 false, f %',ret.x-5,ret.y+(ret.height/2),labels_right[i][5]);}}
59
- var vspace_left=(ca.height-prop['chart.margin.top']-prop['chart.margin.bottom'])/labels_left.length
60
- for(var i=(labels_left.length-1),y=(prop['chart.margin.top']+(vspace_left/2));i>=0;y+=vspace_left,i--){if(labels_left[i][2]){var x=this.centerx-this.radius-offset,idx=labels_left[i][0],explosionX=labels_left[i][6][0]?labels_left[i][6][1]:0,explosionY=labels_left[i][6][0]?labels_left[i][6][2]:0
61
- var ret=RG.text2(this,{font:textConf.font,size:textConf.size,color:textConf.color,bold:textConf.bold,italic:textConf.italic,x:x+explosionX,y:y+explosionY,text:labels_left[i][2],valign:'center',halign:'right',tag:'labels'});if(ret&&ret.node){ret.node.__index__=labels_left[i][0];}
62
- pa2(co,'lw % b m % % qc % % % % s %',prop['chart.labels.sticks.linewidth'],labels_left[i][3][0]+explosionX,labels_left[i][3][1]+explosionY,labels_left[i][4][0]+explosionX,ma.round(labels_left[i][4][1]+explosionY),ret.x+5+ret.width,ret.y+(ret.height/2),labels_left[i][5]);pa2(co,'b a % % 2 0 6.2830 false, f %',ret.x+5+ret.width,ret.y+(ret.height/2),labels_left[i][5]);}}};this.drawSticks=this.DrawSticks=function()
63
- {var offset=prop['chart.linewidth']/2,exploded=prop['chart.exploded'],sticks=prop['chart.labels.sticks'],colors=prop['chart.colors'],cx=this.centerx,cy=this.centery,radius=this.radius,points=[],linewidth=prop['chart.labels.sticks.linewidth']
64
- for(var i=0,len=this.angles.length;i<len;++i){var segment=this.angles[i];if(typeof sticks==='object'&&!sticks[i]){continue;}
65
- var radians=segment[1]-segment[0];co.beginPath();co.strokeStyle=typeof prop['chart.labels.sticks.colors']==='string'?prop['chart.labels.sticks.colors']:(!RG.isNull(prop['chart.labels.sticks.colors'])?prop['chart.labels.sticks.colors'][i]:'gray');co.lineWidth=linewidth;if(typeof prop['chart.labels.sticks.color']==='string'){co.strokeStyle=prop['chart.labels.sticks.color'];}
66
- var midpoint=(segment[0]+(radians/2));if(typeof exploded==='object'&&exploded[i]){var extra=exploded[i];}else if(typeof exploded==='number'){var extra=exploded;}else{var extra=0;}
67
- var stickLength=typeof prop['chart.labels.sticks.length']==='object'?prop['chart.labels.sticks.length'][i]:prop['chart.labels.sticks.length'];points[0]=RG.getRadiusEndPoint(cx,cy,midpoint,radius+extra+offset);points[1]=RG.getRadiusEndPoint(cx,cy,midpoint,radius+stickLength+extra-5);points[2]=RG.getRadiusEndPoint(cx,cy,midpoint,radius+stickLength+extra);points[3]=RG.getRadiusEndPoint(cx,cy,midpoint,radius+stickLength+extra);points[3][0]+=(points[3][0]>cx?5:-5);points[4]=[points[2][0]+(points[2][0]>cx?5+prop['chart.labels.sticks.hlength']:-5-prop['chart.labels.sticks.hlength']),points[2][1]];co.moveTo(points[0][0],points[0][1]);co.quadraticCurveTo(points[2][0],points[2][1],points[4][0],points[4][1]);co.stroke();this.coordsSticks[i]=[points[0],points[1],points[2],points[3],points[4]];}};this.getShape=this.getSegment=function(e)
68
- {RG.FixEventObject(e);var accuracy=arguments[1]?arguments[1]:0;var canvas=ca;var context=co;var mouseCoords=RG.getMouseXY(e);var mouseX=mouseCoords[0];var mouseY=mouseCoords[1];var r=this.radius;var angles=this.angles;var ret=[];for(var i=0,len=angles.length;i<len;++i){co.beginPath();co.strokeStyle='rgba(0,0,0,0)';co.arc(angles[i][2],angles[i][3],this.radius,angles[i][0],angles[i][1],false);if(this.type=='pie'&&prop['chart.variant']=='donut'){co.arc(angles[i][2],angles[i][3],(typeof(prop['chart.variant.donut.width'])=='number'?this.radius-prop['chart.variant.donut.width']:this.radius/2),angles[i][1],angles[i][0],true);}else{co.lineTo(angles[i][2],angles[i][3]);}
69
- co.closePath();if(!co.isPointInPath(mouseX,mouseY)){continue;}
70
- ret[0]=angles[i][2];ret[1]=angles[i][3];ret[2]=this.radius;ret[3]=angles[i][0]-RG.TWOPI;ret[4]=angles[i][1];ret[5]=i;if(ret[3]<0)ret[3]+=RG.TWOPI;if(ret[4]>RG.TWOPI)ret[4]-=RG.TWOPI;var tooltip=RG.parseTooltipText?RG.parseTooltipText(prop['chart.tooltips'],ret[5]):null;ret['object']=this;ret['x']=ret[0];ret['y']=ret[1];ret['radius']=ret[2];ret['angle.start']=ret[3];ret['angle.end']=ret[4];ret['index']=ret[5];ret['tooltip']=tooltip;return ret;}
71
- return null;};this.drawBorders=this.DrawBorders=function()
72
- {if(prop['chart.linewidth']>0){co.lineWidth=prop['chart.linewidth'];co.strokeStyle=prop['chart.colors.stroke'];var r=this.radius;for(var i=0,len=this.angles.length;i<len;++i){var segment=this.angles[i];co.beginPath();co.arc(segment[2],segment[3],r,(segment[0]),(segment[0]+0.001),0);co.arc(segment[2],segment[3],prop['chart.variant']=='donut'?(typeof(prop['chart.variant.donut.width'])=='number'?this.radius-prop['chart.variant.donut.width']:r/2):r,segment[0],segment[0]+0.0001,0);co.closePath();co.stroke();}}};this.getRadius=function()
73
- {this.graph={width:ca.width-prop['chart.margin.left']-prop['chart.margin.right'],height:ca.height-prop['chart.margin.top']-prop['chart.margin.bottom']};if(typeof(prop['chart.radius'])=='number'){this.radius=prop['chart.radius'];}else{this.radius=Math.min(this.graph.width,this.graph.height)/2;}
74
- return this.radius;};this.explodeSegment=this.Explode=function(index,size)
75
- {if(typeof this.exploding==='number'&&this.exploding===index){return;}
76
- if(!prop['chart.exploded']){prop['chart.exploded']=[];}
77
- if(typeof(prop['chart.exploded'])=='number'){var original_explode=prop['chart.exploded'];var exploded=prop['chart.exploded'];prop['chart.exploded']=[];for(var i=0,len=this.data.length;i<len;++i){prop['chart.exploded'][i]=exploded;}}
78
- prop['chart.exploded'][index]=typeof(original_explode)=='number'?original_explode:0;this.exploding=index;var delay=RG.ISIE&&!RG.ISIE10?25:16.666;for(var o=0;o<size;++o){setTimeout(function()
79
- {prop['chart.exploded'][index]+=1;RG.Clear(ca);RG.RedrawCanvas(ca);},o*delay);}
80
- var obj=this;setTimeout(function()
81
- {obj.exploding=null;},size*delay);};this.highlight_segment=function(segment)
82
- {co.beginPath();co.strokeStyle=prop['chart.highlight.style.twod.stroke'];co.fillStyle=prop['chart.highlight.style.twod.fill'];co.moveTo(segment[0],segment[1]);co.arc(segment[0],segment[1],segment[2],this.angles[segment[5]][0],this.angles[segment[5]][1],0);co.lineTo(segment[0],segment[1]);co.closePath();co.stroke();co.fill();};this.highlight=this.Highlight=function(shape)
83
- {if(prop['chart.tooltips.highlight']){if(typeof prop['chart.highlight.style']==='function'){(prop['chart.highlight.style'])(shape);}else if(prop['chart.highlight.style']=='3d'){co.lineWidth=1;var extent=2;co.beginPath();RG.NoShadow(this);co.fillStyle='rgba(0,0,0,0)';co.arc(shape['x'],shape['y'],shape['radius'],shape['angle.start'],shape['angle.end'],false);if(prop['chart.variant']=='donut'){co.arc(shape['x'],shape['y'],shape['radius']/5,shape['angle.end'],shape['angle.start'],true);}else{co.lineTo(shape['x'],shape['y']);}
84
- co.closePath();co.fill();co.beginPath();co.shadowColor='#666';co.shadowBlur=3;co.shadowOffsetX=3;co.shadowOffsetY=3;co.fillStyle=prop['chart.colors'][shape['index']];co.strokeStyle=prop['chart.colors.stroke'];co.arc(shape['x']-extent,shape['y']-extent,shape['radius'],shape['angle.start'],shape['angle.end'],false);if(prop['chart.variant']=='donut'){co.arc(shape['x']-extent,shape['y']-extent,shape['radius']/2,shape['angle.end'],shape['angle.start'],true)}else{co.lineTo(shape['x']-extent,shape['y']-extent);}
85
- co.closePath();co.stroke();co.fill();RG.NoShadow(this);if(prop['chart.border']){co.beginPath();co.strokeStyle=prop['chart.border.color'];co.lineWidth=5;co.arc(shape['x']-extent,shape['y']-extent,shape['radius']-2,shape['angle.start'],shape['angle.end'],false);co.stroke();}}else if(prop['chart.highlight.style']==='outline'){var tooltip=RG.Registry.get('chart.tooltip'),index=tooltip.__index__,coords=this.angles[index],color=this.get('colors')[index]
86
- width=this.radius/12.5;if(typeof prop['chart.highlight.style.outline.width']==='number'){width=prop['chart.highlight.style.outline.width'];}
87
- RGraph.path2(co,'ga 0.25 b a % % % % % false a % % % % % true c f % ga 1',coords[2],coords[3],this.radius+2+width,coords[0],coords[1],coords[2],coords[3],this.radius+2,coords[1],coords[0],color);}else{co.beginPath();co.strokeStyle=prop['chart.highlight.style.twod.stroke'];co.fillStyle=prop['chart.highlight.style.twod.fill'];if(prop['chart.variant'].indexOf('donut')>-1){co.arc(shape['x'],shape['y'],shape['radius'],shape['angle.start'],shape['angle.end'],false);co.arc(shape['x'],shape['y'],typeof(prop['chart.variant.donut.width'])=='number'?this.radius-prop['chart.variant.donut.width']:shape['radius']/2,shape['angle.end'],shape['angle.start'],true);}else{co.arc(shape['x'],shape['y'],shape['radius']+1,shape['angle.start'],shape['angle.end'],false);co.lineTo(shape['x'],shape['y']);}
88
- co.closePath();co.stroke();co.fill();}}};this.getObjectByXY=function(e)
89
- {if(this.getShape(e)){return this;}};this.drawCenterpin=this.DrawCenterpin=function()
90
- {if(typeof prop['chart.centerpin']==='number'&&prop['chart.centerpin']>0){var cx=this.centerx;var cy=this.centery;co.beginPath();co.strokeStyle=prop['chart.centerpin.stroke']?prop['chart.centerpin.stroke']:prop['chart.colors.stroke'];co.fillStyle=prop['chart.centerpin.fill']?prop['chart.centerpin.fill']:prop['chart.colors.stroke'];co.moveTo(cx,cy);co.arc(cx,cy,prop['chart.centerpin'],0,RG.TWOPI,false);co.stroke();co.fill();}};this.drawInGraphLabels=this.DrawInGraphLabels=function()
91
- {var context=co;var cx=this.centerx;var cy=this.centery;var radius=prop['chart.labels.ingraph.radius'];if(radius<=2&&radius>0){radiusFactor=radius;}else{radiusFactor=0.5;}
92
- if(prop['chart.variant']=='donut'){var r=this.radius*(0.5+(radiusFactor*0.5));if(typeof(prop['chart.variant.donut.width'])=='number'){var r=(this.radius-prop['chart.variant.donut.width'])+(prop['chart.variant.donut.width']/2);}}else{var r=this.radius*radiusFactor;}
93
- if(radius>2){r=radius;}
94
- for(var i=0,len=this.angles.length;i<len;++i){if(typeof(prop['chart.exploded'])=='object'&&typeof(prop['chart.exploded'][i])=='number'){var explosion=prop['chart.exploded'][i];}else if(typeof(prop['chart.exploded'])=='number'){var explosion=parseInt(prop['chart.exploded']);}else{var explosion=0;}
95
- var angleStart=this.angles[i][0];var angleEnd=this.angles[i][1];var angleCenter=((angleEnd-angleStart)/2)+angleStart;var coords=RG.getRadiusEndPoint(this.centerx,this.centery,angleCenter,r+(explosion?explosion:0));var x=coords[0];var y=coords[1];var text=prop['chart.labels.ingraph.specific']&&typeof(prop['chart.labels.ingraph.specific'][i])=='string'?prop['chart.labels.ingraph.specific'][i]:RG.numberFormat({object:this,number:this.data[i].toFixed(prop['chart.labels.ingraph.decimals']),unitspre:prop['chart.labels.ingraph.units.pre'],unitspost:prop['chart.labels.ingraph.units.post'],point:prop['chart.labels.ingraph.point'],thousand:prop['chart.labels.ingraph.thousand']});if(text){co.beginPath();var textConf=RG.getTextConf({object:this,prefix:'chart.labels.ingraph'});RG.Text2(this,{font:textConf.font,size:textConf.size,color:textConf.color,bold:textConf.bold,italic:textConf.italic,x:x,y:y,text:text,valign:'center',halign:'center',bounding:prop['chart.labels.ingraph.bounding'],boundingFill:prop['chart.labels.ingraph.bounding.fill'],boundingStroke:prop['chart.labels.ingraph.bounding.stroke'],tag:'labels.ingraph'});co.stroke();}}};this.drawCenterLabel=function(label)
96
- {var textConf=RG.getTextConf({object:this,prefix:'chart.labels.center'});RG.text2(this,{font:textConf.font,size:textConf.size,color:textConf.color,bold:textConf.bold,italic:textConf.italic,x:this.centerx,y:this.centery,halign:'center',valign:'center',text:label,bounding:true,boundingFill:'rgba(255,255,255,0.7)',boundingStroke:'rgba(0,0,0,0)',tag:'labels.center'});};this.getAngle=function(value)
97
- {if(value>this.total){return null;}
98
- var angle=(value/this.total)*RG.TWOPI;angle+=prop['chart.origin'];return angle;};this.parseColors=function()
99
- {if(this.original_colors.length===0){this.original_colors['chart.colors']=RG.arrayClone(prop['chart.colors']);this.original_colors['chart.key.colors']=RG.arrayClone(prop['chart.key.colors']);this.original_colors['chart.colors.stroke']=RG.arrayClone(prop['chart.colors.stroke']);this.original_colors['chart.highlight.stroke']=RG.arrayClone(prop['chart.highlight.stroke']);this.original_colors['chart.highlight.style.twod.fill']=RG.arrayClone(prop['chart.highlight.style.twod.fill']);this.original_colors['chart.highlight.style.twod.stroke']=RG.arrayClone(prop['chart.highlight.style.twod.stroke']);this.original_colors['chart.labels.ingraph.bounding.fill']=RG.arrayClone(prop['chart.labels.ingraph.bounding.fill']);this.original_colors['chart.labels.ingraph.color']=RG.arrayClone(prop['chart.labels.ingraph.color']);}
100
- for(var i=0;i<prop['chart.colors'].length;++i){prop['chart.colors'][i]=this.parseSingleColorForGradient(prop['chart.colors'][i]);}
101
- var keyColors=prop['chart.key.colors'];if(keyColors){for(var i=0;i<keyColors.length;++i){keyColors[i]=this.parseSingleColorForGradient(keyColors[i]);}}
102
- prop['chart.colors.stroke']=this.parseSingleColorForGradient(prop['chart.colors.stroke']);prop['chart.highlight.stroke']=this.parseSingleColorForGradient(prop['chart.highlight.stroke']);prop['chart.highlight.style.twod.fill']=this.parseSingleColorForGradient(prop['chart.highlight.style.twod.fill']);prop['chart.highlight.style.twod.stroke']=this.parseSingleColorForGradient(prop['chart.highlight.style.twod.stroke']);prop['chart.labels.ingraph.bounding.fill']=this.parseSingleColorForGradient(prop['chart.labels.ingraph.bounding.fill']);prop['chart.labels.ingraph.color']=this.parseSingleColorForGradient(prop['chart.labels.ingraph.color']);};this.reset=function()
103
- {};this.parseSingleColorForGradient=function(color)
104
- {if(!color||typeof(color)!='string'){return color;}
105
- if(color.match(/^gradient\((.*)\)$/i)){if(color.match(/^gradient\(({.*})\)$/i)){return RGraph.parseJSONGradient({object:this,def:RegExp.$1});}
106
- var parts=RegExp.$1.split(':');if(prop['chart.variant']=='donut'){var radius_start=typeof(prop['chart.variant.donut.width'])=='number'?this.radius-prop['chart.variant.donut.width']:this.radius/2;}else{var radius_start=0;}
107
- var grad=co.createRadialGradient(this.centerx,this.centery,radius_start,this.centerx,this.centery,Math.min(ca.width-prop['chart.margin.left']-prop['chart.margin.right'],ca.height-prop['chart.margin.top']-prop['chart.margin.bottom'])/2);var diff=1/(parts.length-1);grad.addColorStop(0,RG.trim(parts[0]));for(var j=1;j<parts.length;++j){grad.addColorStop(j*diff,RG.trim(parts[j]));}}
108
- return grad?grad:color;};this.interactiveKeyHighlight=function(index)
109
- {if(this.angles&&this.angles[index]){var segment=this.angles[index];var x=segment[2];var y=segment[3];var start=segment[0];var end=segment[1];co.strokeStyle=prop['chart.key.interactive.highlight.chart.stroke'];co.fillStyle=prop['chart.key.interactive.highlight.chart.fill'];co.lineWidth=2;co.lineJoin='bevel';co.beginPath();co.moveTo(x,y);co.arc(x,y,this.radius,start,end,false);co.closePath();co.fill();co.stroke();}};this.on=function(type,func)
110
- {if(type.substr(0,2)!=='on'){type='on'+type;}
111
- if(typeof this[type]!=='function'){this[type]=func;}else{RG.addCustomEventListener(this,type,func);}
112
- return this;};this.firstDrawFunc=function()
113
- {};this.draw3d=function()
114
- {var scaleX=1.5,depth=prop['chart.variant.threed.depth'],prop_shadow=prop['chart.shadow'],prop_labels=prop['chart.labels'],prop_labelsSticks=prop['chart.labels.sticks']
115
- this.set({labels:[],labelsSticks:false,strokestyle:'rgba(0,0,0,0)'});this.set({variant:this.get('variant').replace(/3d/,'')});this.context.setTransform(scaleX,0,0,1,(ca.width*(scaleX)-ca.width)* -0.5,0);for(var i=depth;i>0;i-=1){this.set({centeryAdjust:i});if(i===parseInt(depth/2)){this.set({labels:prop_labels,labelsSticks:prop_labelsSticks});}
116
- if(i===0){this.set({shadow:prop_shadow});}
117
- this.draw();this.set('shadow',false);if(i<=parseInt(depth/2)){this.set({labels:[],labelsSticks:false});}
118
- if(i>1){if(prop['chart.variant'].indexOf('donut')!==-1){for(var j=0;j<this.angles.length;++j){pa2(co,['b','a',this.angles[j][2],this.angles[j][3],this.radius+1,this.angles[j][0],this.angles[j][1]*prop['chart.effect.roundrobin.multiplier'],false,'a',this.angles[j][2],this.angles[j][3],this.radius/2,this.angles[j][1]*prop['chart.effect.roundrobin.multiplier'],this.angles[j][0],true,'f','rgba(0,0,0,0.15)']);}}else{for(var j=0;j<this.angles.length;++j){pa2(co,['b','m',this.angles[j][2],this.angles[j][3],'a',this.angles[j][2],this.angles[j][3],this.radius+1,this.angles[j][0],this.angles[j][1]*prop['chart.effect.roundrobin.multiplier'],false,'c','f','rgba(0,0,0,0.15)']);}}}}
119
- this.set({variant:this.get('variant')+'3d',shadow:prop_shadow,labels:prop_labels,labelsSticks:prop_labelsSticks});return this;};this.explode=function()
120
- {var obj=this;var opt=arguments[0]?arguments[0]:{};var callback=arguments[1]?arguments[1]:function(){};var frames=opt.frames?opt.frames:30;var frame=0;var maxExplode=Number(typeof opt.radius==='number'?opt.radius:ma.max(ca.width,ca.height));var currentExplode=Number(obj.get('exploded'))||0;var step=(maxExplode-currentExplode)/frames;this.set('labels',null);var iterator=function()
121
- {obj.set('exploded',currentExplode+(step*frame));RGraph.clear(obj.canvas);RGraph.redrawCanvas(obj.canvas);if(frame++<frames){RGraph.Effects.updateCanvas(iterator);}else{callback(obj);}}
122
- iterator();return this;};this.grow=function()
123
- {var obj=this;var canvas=obj.canvas;var opt=arguments[0]?arguments[0]:{};var frames=opt.frames||30;var frame=0;var callback=arguments[1]?arguments[1]:function(){};var radius=obj.getRadius();prop['chart.radius']=0;var iterator=function()
124
- {obj.set('chart.radius',(frame/frames)*radius);RG.redrawCanvas(ca);if(frame++<frames){RG.Effects.updateCanvas(iterator);}else{RG.redrawCanvas(obj.canvas);callback(obj);}};iterator();return this;};this.roundrobin=this.roundRobin=function()
125
- {var obj=this,opt=arguments[0]||{},callback=arguments[1]||function(){},frame=0,frames=opt.frames||30,radius=obj.getRadius(),labels=obj.get('labels')
126
- obj.set('chart.events',false);obj.set('chart.labels',[]);var iterator=function()
127
- {obj.set('effect.roundrobin.multiplier',RG.Effects.getEasingMultiplier(frames,frame));RGraph.redrawCanvas(ca);if(frame++<frames){RGraph.Effects.updateCanvas(iterator);}else{obj.set({events:true,labels:labels});RG.redrawCanvas(obj.canvas);callback(obj);}};iterator();return this;};this.implode=function()
128
- {var obj=this,opt=arguments[0]||{},callback=arguments[1]||function(){},frames=opt.frames||30,frame=0,explodedMax=ma.max(ca.width,ca.height),exploded=explodedMax;function iterator()
129
- {exploded=explodedMax-((frame/frames)*explodedMax);obj.Set('exploded',exploded);RG.clear(ca);RG.redrawCanvas(ca);if(frame++<frames){RG.Effects.updateCanvas(iterator);}else{RG.clear(obj.canvas);RG.redrawCanvas(obj.canvas);callback(obj);}}
130
- iterator();return this;};RG.register(this);if(parseConfObjectForOptions){RG.parseObjectStyleConfig(this,conf.options);}};
12
+ RGraph = window.RGraph || {isrgraph:true,isRGraph:true,rgraph:true};
13
+
14
+ //
15
+ // The pie chart constructor
16
+ //
17
+ RGraph.Pie = function (conf)
18
+ {
19
+ var id = conf.id,
20
+ canvas = document.getElementById(id),
21
+ data = conf.data;
22
+
23
+ // Get the canvas and context objects
24
+ this.id = id;
25
+ this.canvas = canvas;
26
+ this.context = this.canvas.getContext ? this.canvas.getContext("2d", {alpha: (typeof id === 'object' && id.alpha === false) ? false : true}) : null;
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
+ this.isrgraph = true;
36
+ this.rgraph = true;
37
+ this.coords = [];
38
+ this.coords.key = [];
39
+ this.coordsSticks = [];
40
+ this.coordsText = [];
41
+ this.uid = RGraph.createUID();
42
+ this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.createUID();
43
+ this.colorsParsed = false;
44
+ this.original_colors = [];
45
+ this.firstDraw = true; // After the first draw this will be false
46
+ this.exploding = null;
47
+ this.stopAnimationRequested = false;// Used to control the animations
48
+
49
+
50
+
51
+
52
+
53
+ //
54
+ // Convert strings to numbers
55
+ //
56
+ this.data = RGraph.stringsToNumbers(this.data);
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+ this.properties =
65
+ {
66
+ centerxAdjust: 0,
67
+ centeryAdjust: 0,
68
+
69
+ colors: ['red', '#ccc', '#cfc', 'blue', 'pink', 'yellow', 'black', 'orange', 'cyan', 'purple', '#78CAEA', '#E284E9', 'white', 'blue', '#9E7BF6'],
70
+ colorsStroke: 'white',
71
+
72
+ linewidth: 3,
73
+
74
+ labels: [],
75
+ labelsFormattedDecimals: 0,
76
+ labelsFormattedPoint: '.',
77
+ labelsFormattedThousand: ',',
78
+ labelsFormattedUnitsPre: '',
79
+ labelsFormattedUnitsPost: '',
80
+ labelsFont: null,
81
+ labelsSize: null,
82
+ labelsColor: null,
83
+ labelsBold: null,
84
+ labelsItalic: null,
85
+ labelsRadiusOffset: 0,
86
+ labelsSticks: false,
87
+ labelsSticksLength: 7,
88
+ labelsSticksColors: null,
89
+ labelsSticksLinewidth: 1,
90
+ labelsSticksHlength: 5,
91
+ labelsList: true,
92
+ labelsListLeftOffsetx: 0,
93
+ labelsListLeftOffsety: 0,
94
+ labelsListRightOffsetx: 0,
95
+ labelsListRightOffsety: 0,
96
+
97
+ labelsIngraph: null,
98
+ labelsIngraphColor: null,
99
+ labelsIngraphFont: null,
100
+ labelsIngraphSize: null,
101
+ labelsIngraphBold: null,
102
+ labelsIngraphItalic: null,
103
+ labelsIngraphBounding: true,
104
+ labelsIngraphBoundingFill: 'rgba(255,255,255,0.85)',
105
+ labelsIngraphBoundingStroke: 'rgba(0,0,0,0)',
106
+ labelsIngraphSpecific: null,
107
+ labelsIngraphSpecificFormattedDecimals: 0,
108
+ labelsIngraphSpecificFormattedPoint: '.',
109
+ labelsIngraphSpecificFormattedThousand: ',',
110
+ labelsIngraphSpecificFormattedUnitsPre: '',
111
+ labelsIngraphSpecificFormattedUnitsPost: '',
112
+ labelsIngraphUnitsPre: '',
113
+ labelsIngraphUnitsPost: '',
114
+ labelsIngraphPoint: '.',
115
+ labelsIngraphThousand: ',',
116
+ labelsIngraphDecimals: 0,
117
+ labelsIngraphRadius: null,
118
+ labelsIngraphRadiusOffset: 0,
119
+ labelsIngraphUndrawn: null,
120
+ labelsIngraphUndrawnAsLabels: null,
121
+ labelsIngraphUndrawnAlwaysShow: false,
122
+
123
+ labelsCenter: null,
124
+ labelsCenterSize: 26,
125
+ labelsCenterFont: null,
126
+ labelsCenterColor: null,
127
+ labelsCenterItalic: null,
128
+ labelsCenterBold: null,
129
+ labelsCenterOffsetx: 0,
130
+ labelsCenterOffsety: 0,
131
+
132
+ labelsInside: null,
133
+ labelsInsideColor: null,
134
+ labelsInsideSize: null,
135
+ labelsInsideFont: null,
136
+ labelsInsideBold: null,
137
+ labelsInsideItalic: null,
138
+ labelsInsideDecimals: 0,
139
+ labelsInsidePoint: '.',
140
+ labelsInsideThousand: ',',
141
+ labelsInsideUnitsPre: '',
142
+ labelsInsideUnitsPost: '',
143
+ labelsInsideOffsetr: 0,
144
+ labelsInsideHalign: 'auto',
145
+ labelsInsideBounding: false,
146
+ labelsInsideBoundingFill: 'rgba(255,255,255,0.75)',
147
+ labelsInsideBoundingStroke: 'transparent',
148
+ labelsInsideSpecific: null,
149
+ labelsInsideSpecificFormattedDecimals: 0,
150
+ labelsInsideSpecificFormattedPoint: '.',
151
+ labelsInsideSpecificFormattedThousand: ',',
152
+ labelsInsideSpecificFormattedUnitsPre: '',
153
+ labelsInsideSpecificFormattedUnitsPost: '',
154
+
155
+ marginLeft: 35,
156
+ marginRight: 35,
157
+ marginTop: 35,
158
+ marginBottom: 35,
159
+
160
+ title: '',
161
+ titleBold: null,
162
+ titleFont: null,
163
+ titleSize: null,
164
+ titleColor: null,
165
+ titleItalic: null,
166
+ titleX: null,
167
+ titleY: null,
168
+ titleHalign: null,
169
+ titleValign: null,
170
+ titleOffsetx: 0,
171
+ titleOffsety: 0,
172
+ titleSubtitle: '',
173
+ titleSubtitleSize: null,
174
+ titleSubtitleColor: '#aaa',
175
+ titleSubtitleFont: null,
176
+ titleSubtitleBold: null,
177
+ titleSubtitleItalic: null,
178
+ titleSubtitleOffsetx: 0,
179
+ titleSubtitleOffsety: 0,
180
+
181
+ shadow: true,
182
+ shadowColor: '#aaa',
183
+ shadowOffsetx: 0,
184
+ shadowOffsety: 0,
185
+ shadowBlur: 15,
186
+
187
+ textBold: false,
188
+ textItalic: false,
189
+ textSize: 12,
190
+ textColor: 'black',
191
+ textFont: 'Arial, Verdana, sans-serif',
192
+ textAccessible: false,
193
+ textAccessibleOverflow: 'visible',
194
+ textAccessiblePointerevents: false,
195
+ text: null,
196
+
197
+ contextmenu: null,
198
+
199
+ tooltips: [],
200
+ tooltipsEvent: 'onclick',
201
+ tooltipsEffect: 'slide',
202
+ tooltipsCssClass: 'RGraph_tooltip',
203
+ tooltipsCss: null,
204
+ tooltipsHighlight: true,
205
+ tooltipsFormattedThousand: ',',
206
+ tooltipsFormattedPoint: '.',
207
+ tooltipsFormattedDecimals: 0,
208
+ tooltipsFormattedUnitsPre: '',
209
+ tooltipsFormattedUnitsPost: '',
210
+ tooltipsFormattedKeyColors: null,
211
+ tooltipsFormattedKeyColorsShape: 'square',
212
+ tooltipsFormattedKeyLabels: [],
213
+ tooltipsFormattedListType: 'ul',
214
+ tooltipsFormattedListItems: null,
215
+ tooltipsFormattedTableHeaders: null,
216
+ tooltipsFormattedTableData: null,
217
+ tooltipsPointer: true,
218
+ tooltipsPointerOffsetx: 0,
219
+ tooltipsPointerOffsety: 0,
220
+ tooltipsPositionStatic: true,
221
+ tooltipsHotspotIgnore: null,
222
+
223
+ highlightStyle: '2d',
224
+ highlightStyleTwodFill: 'rgba(255,255,255,0.7)',
225
+ highlightStyleTwodStroke: 'transparent',
226
+ highlightStyleTwodLinewidth: 2,
227
+ highlightStyleOutlineWidth: null,
228
+
229
+ centerx: null,
230
+ centery: null,
231
+ radius: null,
232
+
233
+ border: false,
234
+ borderColor: 'rgba(255,255,255,0.5)',
235
+
236
+ key: null,
237
+ keyBackground: 'white',
238
+ keyPosition: 'graph',
239
+ keyHalign: 'right',
240
+ keyValign: null,
241
+ keyShadow: false,
242
+ keyShadowColor: '#666',
243
+ keyShadowBlur: 3,
244
+ keyShadowOffsetx: 2,
245
+ keyShadowOffsety: 2,
246
+ keyPositionGutterBoxed: false,
247
+ keyPositionX: null,
248
+ keyPositionY: null,
249
+ keyColorShape: 'square',
250
+ keyRounded: true,
251
+ keyLinewidth: 1,
252
+ keyColors: null,
253
+ keyInteractive: false,
254
+ keyInteractiveHighlightChartStroke: 'black',
255
+ keyInteractiveHighlightChartFill: 'rgba(255,255,255,0.7)',
256
+ keyInteractiveHighlightLabel: 'rgba(255,0,0,0.2)',
257
+ keyLabelsColor: null,
258
+ keyLabelsFont: null,
259
+ keyLabelsSize: null,
260
+ keyLabelsBold: null,
261
+ keyLabelsItalic: null,
262
+ keyLabelsOffsetx: 0,
263
+ keyLabelsOffsety: 0,
264
+ keyFormattedDecimals: 0,
265
+ keyFormattedPoint: '.',
266
+ keyFormattedThousand: ',',
267
+ keyFormattedUnitsPre: '',
268
+ keyFormattedUnitsPost: '',
269
+ keyFormattedValueSpecific: null,
270
+ keyFormattedItemsCount: null,
271
+
272
+ annotatable: false,
273
+ annotatableColor: 'black',
274
+
275
+ variant: 'pie',
276
+ variantDonutWidth: null,
277
+ variantThreedDepth: 20,
278
+
279
+ exploded: [],
280
+
281
+ effectRoundrobinMultiplier: 1,
282
+
283
+ centerpin: null,
284
+ centerpinFill: 'gray',
285
+ centerpinStroke: 'white',
286
+
287
+ origin: 0 - (Math.PI / 2),
288
+
289
+ clearto: 'rgba(0,0,0,0)',
290
+ events: true
291
+ }
292
+
293
+
294
+
295
+ //
296
+ // Calculate the total
297
+ //
298
+ for (var i=0,len=data.length; i<len; i++) {
299
+ this.total += data[i];
300
+
301
+ // This loop also creates the $xxx objects - this isn't related to
302
+ // the code above but just saves doing another loop through the data
303
+ this['$' + i] = {};
304
+ }
305
+
306
+
307
+
308
+
309
+ // Easy access to properties and the path function
310
+ var properties = this.properties;
311
+ this.path = RGraph.pathObjectFunction;
312
+
313
+
314
+
315
+ //
316
+ // "Decorate" the object with the generic effects if the effects library has been included
317
+ //
318
+ if (RGraph.Effects && typeof RGraph.Effects.decorate === 'function') {
319
+ RGraph.Effects.decorate(this);
320
+ }
321
+
322
+
323
+
324
+ // Add the responsive method. This method resides in the common file.
325
+ this.responsive = RGraph.responsive;
326
+
327
+
328
+
329
+
330
+
331
+
332
+
333
+
334
+ //
335
+ // A generic setter
336
+ //
337
+ this.set = function (name)
338
+ {
339
+ var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
340
+
341
+ // Accommodate some BC
342
+ if (name === 'labelsOffsetRadius') {
343
+ name = 'labelsRadiusOffset';
344
+ }
345
+
346
+ // the number of arguments is only one and it's an
347
+ // object - parse it for configuration data and return.
348
+ if (arguments.length === 1 && typeof arguments[0] === 'object') {
349
+ for (i in arguments[0]) {
350
+ if (typeof i === 'string') {
351
+ this.set(i, arguments[0][i]);
352
+ }
353
+ }
354
+
355
+
356
+
357
+ return this;
358
+ }
359
+
360
+ properties[name] = value;
361
+
362
+ return this;
363
+ };
364
+
365
+
366
+
367
+
368
+
369
+
370
+
371
+
372
+ //
373
+ // A generic getter
374
+ //
375
+ this.get = function (name)
376
+ {
377
+ return properties[name];
378
+ };
379
+
380
+
381
+
382
+
383
+
384
+
385
+
386
+
387
+ //
388
+ // This draws the pie chart
389
+ //
390
+ this.draw = function ()
391
+ {
392
+ //
393
+ // Fire the onbeforedraw event
394
+ //
395
+ RGraph.fireCustomEvent(this, 'onbeforedraw');
396
+
397
+
398
+
399
+ // Translate half a pixel for antialiasing purposes - but only if it hasn't been
400
+ // done already
401
+ //
402
+ // MUST be the first thing done!
403
+ //
404
+ if (!this.canvas.__rgraph_aa_translated__) {
405
+ this.context.translate(0.5,0.5);
406
+
407
+ this.canvas.__rgraph_aa_translated__ = true;
408
+ }
409
+
410
+ // NB: Colors are parsed further down so that the center X/Y can be used
411
+
412
+
413
+
414
+
415
+ //
416
+ // Make the margins easy ro access
417
+ //
418
+ this.marginLeft = properties.marginLeft;
419
+ this.marginRight = properties.marginRight;
420
+ this.marginTop = properties.marginTop;
421
+ this.marginBottom = properties.marginBottom;
422
+
423
+ this.radius = this.getRadius();// MUST be first
424
+ this.centerx = (this.graph.width / 2) + this.marginLeft + properties.centerxAdjust;
425
+ this.centery = (this.graph.height / 2) + this.marginTop + properties.centeryAdjust;
426
+ this.subTotal = properties.origin;
427
+ this.angles = [];
428
+ this.coordsText = [];
429
+
430
+ //
431
+ // Allow specification of a custom radius & center X/Y
432
+ //
433
+ if (typeof properties.radius === 'number') this.radius = properties.radius;
434
+ if (typeof properties.centerx === 'number') this.centerx = properties.centerx;
435
+ if (typeof properties.centery === 'number') this.centery = properties.centery;
436
+
437
+
438
+ if (this.radius <= 0) {
439
+ return;
440
+ }
441
+
442
+ //
443
+ // Parse the colors for gradients. Its down here so that the center X/Y can be used
444
+ //
445
+ if (!this.colorsParsed) {
446
+
447
+ this.parseColors();
448
+
449
+ // Don't want to do this again
450
+ this.colorsParsed = true;
451
+ }
452
+
453
+
454
+ if (properties.variant.indexOf('3d') > 0) {
455
+ return this.draw3d();
456
+ }
457
+
458
+
459
+
460
+
461
+ //
462
+ // Draw the title
463
+ //
464
+ this.drawTitle();
465
+
466
+ //
467
+ // The total of the array of values
468
+ //
469
+ this.total = RGraph.arraySum(this.data);
470
+ var tot = this.total;
471
+ var data = this.data;
472
+
473
+ for (var i=0,len=this.data.length; i<len; i++) {
474
+
475
+ var angle = ((data[i] / tot) * RGraph.TWOPI);
476
+
477
+ // Draw the segment
478
+ this.drawSegment(angle,properties.colors[i],i == (len - 1), i);
479
+ }
480
+
481
+ RGraph.noShadow(this);
482
+
483
+ //
484
+ // Redraw the seperating lines
485
+ //
486
+ if (properties.linewidth > 0) {
487
+ this.drawBorders();
488
+ }
489
+
490
+ //
491
+ // Now draw the segments again with shadow turned off. This is always performed,
492
+ // not just if the shadow is on.
493
+ //
494
+ var len = this.angles.length;
495
+ var r = this.radius;
496
+
497
+
498
+ for (var action=0; action<2; action+=1) {
499
+ for (var i=0; i<len; i++) {
500
+
501
+ this.context.beginPath();
502
+
503
+ var segment = this.angles[i];
504
+
505
+ if (action === 1) {
506
+ this.context.strokeStyle = typeof properties.colorsStroke == 'object' ? properties.colorsStroke[i] : properties.colorsStroke;
507
+ }
508
+ properties.colors[i] ? this.context.fillStyle = properties.colors[i] : null;
509
+ this.context.lineJoin = 'round';
510
+
511
+ this.context.arc(
512
+ segment[2],
513
+ segment[3],
514
+ r,
515
+ (segment[0]),
516
+ (segment[1]),
517
+ false
518
+ );
519
+ if (properties.variant == 'donut') {
520
+
521
+ this.context.arc(
522
+ segment[2],
523
+ segment[3],
524
+ typeof properties.variantDonutWidth == 'number' ? r - properties.variantDonutWidth : r / 2,
525
+ (segment[1]),
526
+ (segment[0]),
527
+ true
528
+ );
529
+
530
+ } else {
531
+ this.context.lineTo(segment[2], segment[3]);
532
+ }
533
+ this.context.closePath();
534
+ action === 0 ? this.context.fill() : this.context.stroke();
535
+ }
536
+ }
537
+
538
+
539
+
540
+
541
+ //
542
+ // Draw label sticks
543
+ //
544
+ if (properties.labelsSticks) {
545
+
546
+ this.drawSticks();
547
+
548
+ // Redraw the border going around the Pie chart if the stroke style is NOT white
549
+ var strokeStyle = properties.colorsStroke;
550
+ }
551
+
552
+ //
553
+ // Draw the labels
554
+ //
555
+ if (properties.labels) {
556
+ this.drawLabels();
557
+ }
558
+
559
+
560
+ //
561
+ // Draw centerpin if requested
562
+ //
563
+ if (properties.centerpin) {
564
+ this.drawCenterpin();
565
+ }
566
+
567
+
568
+
569
+
570
+ //
571
+ // Draw ingraph labels
572
+ //
573
+ if (properties.labelsIngraph) {
574
+ this.drawInGraphLabels();
575
+ }
576
+
577
+
578
+
579
+
580
+ //
581
+ // Draw the center label if requested
582
+ //
583
+ if (typeof properties.labelsCenter === 'string') {
584
+ this.drawCenterLabel(properties.labelsCenter);
585
+ }
586
+
587
+ // Draw the labelsInside labels. Mainly for donut
588
+ // charts - but you can use them if you choose
589
+ if (properties.labelsInside) {
590
+ this.drawLabelsInside();
591
+ }
592
+
593
+
594
+ //
595
+ // Setup the context menu if required
596
+ //
597
+ if (properties.contextmenu) {
598
+ RGraph.showContext(this);
599
+ }
600
+
601
+
602
+
603
+ //
604
+ // If a border is pecified, draw it
605
+ //
606
+ if (properties.border) {
607
+ this.context.beginPath();
608
+ this.context.lineWidth = 5;
609
+ this.context.strokeStyle = properties.borderColor;
610
+
611
+ this.context.arc(
612
+ this.centerx,
613
+ this.centery,
614
+ this.radius - 2,
615
+ 0,
616
+ RGraph.TWOPI,
617
+ 0
618
+ );
619
+
620
+ this.context.stroke();
621
+ }
622
+
623
+ //
624
+ // Draw the key if desired
625
+ //
626
+ if (properties.key && properties.key.length) {
627
+
628
+ // Allow for vertical centering
629
+ if (properties.keyValign === 'center') {
630
+
631
+ // Calculate how big the key labels are
632
+ var textConf = RGraph.getTextConf({
633
+ object: this,
634
+ prefix: 'keyLabels'
635
+ });
636
+
637
+ // Calculate the height of the key
638
+ var height = this.properties.key.length * textConf.size * 1.5;
639
+
640
+ // Use the height that has just been calculate to set
641
+ // the new Y coordinate of the key
642
+ this.set('keyPositionY', this.centery - (height / 2));
643
+ }
644
+
645
+
646
+
647
+
648
+
649
+ RGraph.drawKey(
650
+ this,
651
+ properties.key,
652
+ properties.colors
653
+ );
654
+ }
655
+
656
+ RGraph.noShadow(this);
657
+
658
+
659
+
660
+
661
+ //
662
+ // Add custom text thats specified
663
+ //
664
+ RGraph.addCustomText(this);
665
+
666
+
667
+
668
+
669
+
670
+
671
+
672
+
673
+
674
+ //
675
+ // This installs the event listeners
676
+ //
677
+ if (properties.events == true) {
678
+ RGraph.installEventListeners(this);
679
+ }
680
+
681
+
682
+ //
683
+ // Fire the onfirstdraw event
684
+ //
685
+ if (this.firstDraw) {
686
+ this.firstDraw = false;
687
+ RGraph.fireCustomEvent(this, 'onfirstdraw');
688
+ this.firstDrawFunc();
689
+ }
690
+
691
+
692
+
693
+
694
+ //
695
+ // Fire the RGraph draw event
696
+ //
697
+ RGraph.fireCustomEvent(this, 'ondraw');
698
+
699
+
700
+
701
+
702
+
703
+
704
+
705
+
706
+ //
707
+ // Install any inline responsive configuration. This
708
+ // should be last in the draw function - even after
709
+ // the draw events.
710
+ //
711
+ RGraph.installInlineResponsive(this);
712
+
713
+
714
+
715
+
716
+
717
+
718
+
719
+
720
+
721
+
722
+ return this;
723
+ };
724
+
725
+
726
+
727
+
728
+
729
+
730
+
731
+
732
+ //
733
+ // Used in chaining. Runs a function there and then - not waiting for
734
+ // the events to fire (eg the onbeforedraw event)
735
+ //
736
+ // @param function func The function to execute
737
+ //
738
+ this.exec = function (func)
739
+ {
740
+ func(this);
741
+
742
+ return this;
743
+ };
744
+
745
+
746
+
747
+
748
+
749
+
750
+
751
+
752
+ //
753
+ // Draws the title
754
+ //
755
+ this.drawTitle = function ()
756
+ {
757
+ RGraph.drawTitle(this);
758
+ };
759
+
760
+
761
+
762
+
763
+
764
+
765
+
766
+
767
+ //
768
+ // Draws a single segment of the pie chart
769
+ //
770
+ // @param int degrees The number of degrees for this segment
771
+ //
772
+ this.drawSegment = function (radians, color, last, index)
773
+ {
774
+ // IE7/8/ExCanvas fix (when there's only one segment the Pie chart doesn't display
775
+ //if (RGraph.ISOLD && radians == RGraph.TWOPI) {
776
+ // radians -= 0.0001;
777
+ //} else if (RGraph.ISOLD && radians == 0) {
778
+ // radians = 0.001;
779
+ //}
780
+
781
+ var subTotal = this.subTotal;
782
+ radians = radians * properties.effectRoundrobinMultiplier;
783
+
784
+ this.context.beginPath();
785
+
786
+ color ? this.context.fillStyle = color : null;
787
+ this.context.strokeStyle = properties.colorsStroke;
788
+ this.context.lineWidth = 0;
789
+
790
+ if (properties.shadow) {
791
+ RGraph.setShadow(
792
+ this,
793
+ properties.shadowColor,
794
+ properties.shadowOffsetx,
795
+ properties.shadowOffsety,
796
+ properties.shadowBlur
797
+ );
798
+ }
799
+
800
+ //
801
+ // Exploded segments
802
+ //
803
+ if ( (typeof properties.exploded == 'object' && properties.exploded[index] > 0) || typeof properties.exploded == 'number') {
804
+
805
+ var explosion = typeof properties.exploded == 'number' ? properties.exploded : properties.exploded[index];
806
+ var x = 0;
807
+ var y = 0;
808
+ var h = explosion;
809
+ var t = subTotal + (radians / 2);
810
+ var x = (Math.cos(t) * explosion);
811
+ var y = (Math.sin(t) * explosion);
812
+ var r = this.radius;
813
+
814
+ this.context.moveTo(this.centerx + x, this.centery + y);
815
+ } else {
816
+ var x = 0;
817
+ var y = 0;
818
+ var r = this.radius;
819
+ }
820
+
821
+ //
822
+ // Calculate the angles
823
+ //
824
+ var startAngle = subTotal;
825
+ var endAngle = ((subTotal + radians));
826
+
827
+ this.context.arc(this.centerx + x,
828
+ this.centery + y,
829
+ r,
830
+ startAngle,
831
+ endAngle,
832
+ 0);
833
+
834
+ if (properties.variant == 'donut') {
835
+
836
+ this.context.arc(
837
+ this.centerx + x,
838
+ this.centery + y,
839
+ typeof properties.variantDonutWidth == 'number' ? r - properties.variantDonutWidth : r / 2,
840
+ endAngle,
841
+ startAngle,
842
+ true
843
+ );
844
+ } else {
845
+ this.context.lineTo(this.centerx + x, this.centery + y);
846
+ }
847
+
848
+ this.context.closePath();
849
+
850
+
851
+ // Keep hold of the angles
852
+ this.angles.push([
853
+ subTotal,
854
+ subTotal + radians,
855
+ this.centerx + x,
856
+ this.centery + y
857
+ ]);
858
+
859
+
860
+
861
+ //this.context.stroke();
862
+ this.context.fill();
863
+
864
+ //
865
+ // Calculate the segment angle
866
+ //
867
+ this.subTotal += radians;
868
+ };
869
+
870
+
871
+
872
+
873
+
874
+
875
+
876
+
877
+ //
878
+ // Draws the graphs labels
879
+ //
880
+ this.drawLabels = function ()
881
+ {
882
+ if (properties.labels && properties.labels.length) {
883
+ //
884
+ // If the xaxisLabels option is a string then turn it
885
+ // into an array.
886
+ //
887
+ if (typeof properties.labels === 'string') {
888
+ properties.labels = RGraph.arrayPad({
889
+ array: [],
890
+ length: this.data.length,
891
+ value: properties.labels
892
+ });
893
+ }
894
+
895
+ for (var i=0; i<properties.labels.length; ++i) {
896
+
897
+ // Only do substitution if it's a string or
898
+ // a number
899
+ if (RGraph.isTextual(properties.labels[i])) {
900
+
901
+ properties.labels[i] = RGraph.labelSubstitution({
902
+ object: this,
903
+ text: properties.labels[i],
904
+ index: i,
905
+ value: this.data[i],
906
+ decimals: properties.labelsFormattedDecimals || 0,
907
+ unitsPre: properties.labelsFormattedUnitsPre || '',
908
+ unitsPost: properties.labelsFormattedUnitsPost || '',
909
+ thousand: properties.labelsFormattedThousand || ',',
910
+ point: properties.labelsFormattedPoint || '.'
911
+ });
912
+ }
913
+ }
914
+ }
915
+
916
+
917
+
918
+
919
+ // New way of spacing labels out
920
+ if (properties.labels.length && properties.labelsList) {
921
+ return this.drawLabelsList();
922
+ }
923
+
924
+
925
+
926
+
927
+
928
+
929
+
930
+
931
+ var hAlignment = 'left',
932
+ vAlignment = 'center',
933
+ labels = properties.labels,
934
+ context = this.context,
935
+ font = properties.textFont,
936
+ bold = properties.labelsBold,
937
+ text_size = properties.textSize,
938
+ cx = this.centerx,
939
+ cy = this.centery,
940
+ r = this.radius;
941
+
942
+ //
943
+ // Turn the shadow off
944
+ //
945
+ RGraph.noShadow(this);
946
+
947
+ this.context.fillStyle = 'black';
948
+ this.context.beginPath();
949
+
950
+ //
951
+ // Draw the labels
952
+ //
953
+ if (labels && labels.length) {
954
+
955
+ var textConf = RGraph.getTextConf({
956
+ object: this,
957
+ prefix: 'labels'
958
+ });
959
+
960
+ for (i=0; i<this.angles.length; ++i) {
961
+
962
+ var segment = this.angles[i];
963
+
964
+ if (typeof labels[i] != 'string' && typeof labels[i] != 'number') {
965
+ continue;
966
+ }
967
+
968
+ // Move to the centre
969
+ this.context.moveTo(cx,cy);
970
+
971
+ var a = segment[0] + ((segment[1] - segment[0]) / 2),
972
+ angle = ((segment[1] - segment[0]) / 2) + segment[0];
973
+
974
+ //
975
+ // Handle the additional "explosion" offset
976
+ //
977
+ if (typeof properties.exploded === 'object' && properties.exploded[i] || typeof properties.exploded == 'number') {
978
+
979
+ var t = ((segment[1] - segment[0]) / 2),
980
+ seperation = typeof properties.exploded == 'number' ? properties.exploded : properties.exploded[i];
981
+
982
+ // Adjust the angles
983
+ var explosion_offsetx = (Math.cos(angle) * seperation),
984
+ explosion_offsety = (Math.sin(angle) * seperation);
985
+ } else {
986
+ var explosion_offsetx = 0,
987
+ explosion_offsety = 0;
988
+ }
989
+
990
+ //
991
+ // Allow for the label sticks
992
+ //
993
+ if (properties.labelsSticks) {
994
+ explosion_offsetx += (Math.cos(angle) * (typeof properties.labelsSticksLength === 'object' ? properties.labelsSticksLength[i] : properties.labelsSticksLength) );
995
+ explosion_offsety += (Math.sin(angle) * (typeof properties.labelsSticksLength === 'object' ? properties.labelsSticksLength[i] : properties.labelsSticksLength) );
996
+ }
997
+
998
+ //
999
+ // Coords for the text
1000
+ //
1001
+ var x = cx + explosion_offsetx + ((r + 10 + properties.labelsRadiusOffset) * Math.cos(a)) + (properties.labelsSticks ? (a < RGraph.HALFPI || a > (RGraph.TWOPI + RGraph.HALFPI) ? 2 : -2) : 0),
1002
+ y = cy + explosion_offsety + (((r + 10 + properties.labelsRadiusOffset) * Math.sin(a)));
1003
+
1004
+
1005
+
1006
+
1007
+ //
1008
+ // If sticks are enabled use the endpoints that have been saved
1009
+ //
1010
+ if (this.coordsSticks && this.coordsSticks[i]) {
1011
+ var x = this.coordsSticks[i][4][0] + (x < cx ? -5 : 5),
1012
+ y = this.coordsSticks[i][4][1];
1013
+ }
1014
+
1015
+
1016
+ //
1017
+ // Alignment
1018
+ //
1019
+ //vAlignment = y < cy ? 'center' : 'center';
1020
+ vAlignment = 'center';
1021
+ hAlignment = x < cx ? 'right' : 'left';
1022
+
1023
+ this.context.fillStyle = properties.textColor;
1024
+ //if ( typeof properties.labelsColors === 'object' && properties.labelsColors && properties.labelsColors[i]) {
1025
+ // this.context.fillStyle = properties.labelsColors[i];
1026
+ //}
1027
+
1028
+ RGraph.text({
1029
+
1030
+ object: this,
1031
+
1032
+ font: textConf.font,
1033
+ size: textConf.size,
1034
+ color: textConf.color,
1035
+ bold: textConf.bold,
1036
+ italic: textConf.italic,
1037
+
1038
+ x: x,
1039
+ y: y,
1040
+ text: labels[i],
1041
+ valign: vAlignment,
1042
+ halign: hAlignment,
1043
+ tag: 'labels',
1044
+ cssClass: RGraph.getLabelsCSSClassName({
1045
+ object: this,
1046
+ name: 'labelsClass',
1047
+ index: i
1048
+ })
1049
+ });
1050
+ }
1051
+
1052
+ this.context.fill();
1053
+ }
1054
+ };
1055
+
1056
+
1057
+
1058
+
1059
+
1060
+
1061
+
1062
+
1063
+ //
1064
+ // A newer way of spacing out labels
1065
+ //
1066
+ this.drawLabelsList = function ()
1067
+ {
1068
+ var segment = this.angles[i],
1069
+ labels = properties.labels,
1070
+ labels_right = [],
1071
+ labels_left = [],
1072
+ left = [],
1073
+ right = [],
1074
+ centerx = this.centerx,
1075
+ centery = this.centery,
1076
+ radius = this.radius,
1077
+ offset = 50 // This may not be used - see the endpoint_outer var below
1078
+
1079
+
1080
+
1081
+
1082
+
1083
+
1084
+
1085
+
1086
+
1087
+ //
1088
+ // Draw the right hand side labels
1089
+ //
1090
+ for (var i=0; i<this.angles.length; ++i) {
1091
+
1092
+ // Null values do not get labels displayed. Also,
1093
+ // null or undefined labels aren't displayed either
1094
+ if (RGraph.isNull(this.data[i])) {
1095
+ continue;
1096
+ }
1097
+
1098
+ var angle = this.angles[i][0] + ((this.angles[i][1] - this.angles[i][0]) / 2), // Midpoint
1099
+ endpoint_inner = RGraph.getRadiusEndPoint(centerx, centery, angle, radius + 5),
1100
+ endpoint_outer = RGraph.getRadiusEndPoint(centerx, centery, angle, radius + 30),
1101
+ explosion = [
1102
+ (typeof properties.exploded === 'number' ? properties.exploded : properties.exploded[i]),
1103
+ (Math.cos(angle) * (typeof properties.exploded === 'number' ? properties.exploded : properties.exploded[i])),
1104
+ (Math.sin(angle) * (typeof properties.exploded === 'number' ? properties.exploded : properties.exploded[i]))
1105
+ ]
1106
+
1107
+ var textConf = RGraph.getTextConf({
1108
+ object: this,
1109
+ prefix: 'labels'
1110
+ });
1111
+
1112
+
1113
+
1114
+
1115
+ if (angle > (-1 * RGraph.HALFPI) && angle < RGraph.HALFPI) {
1116
+ labels_right.push([
1117
+ i,
1118
+ angle,
1119
+ labels[i] ? labels[i] : '',
1120
+ endpoint_inner,
1121
+ endpoint_outer,
1122
+ textConf.color,
1123
+ RGraph.arrayClone(explosion)
1124
+ ]);
1125
+ } else {
1126
+ labels_left.push([
1127
+ i,
1128
+ angle,
1129
+ labels[i] ? labels[i] : '',
1130
+ endpoint_inner,
1131
+ endpoint_outer,
1132
+ textConf.color,
1133
+ RGraph.arrayClone(explosion)
1134
+ ]);
1135
+ }
1136
+ }
1137
+
1138
+
1139
+
1140
+
1141
+ //
1142
+ // Draw the right hand side labels first
1143
+ //
1144
+
1145
+
1146
+ // Calculate how much space there is for each label
1147
+ var vspace_right = (this.canvas.height - properties.marginTop - properties.marginBottom) / labels_right.length;
1148
+
1149
+
1150
+ for (var i=0,y=(properties.marginTop + (vspace_right / 2)); i<labels_right.length; y+=vspace_right,i++) {
1151
+
1152
+ if (labels_right[i][2]) {
1153
+
1154
+ var x = this.centerx + this.radius + offset,
1155
+ idx = labels_right[i][0],
1156
+ explosionX = labels_right[i][6][0] ? labels_right[i][6][1] : 0,
1157
+ explosionY = labels_right[i][6][0] ? labels_right[i][6][2] : 0
1158
+
1159
+ var ret = RGraph.text({
1160
+ object: this,
1161
+ font: textConf.font,
1162
+ size: textConf.size,
1163
+ color: textConf.color,
1164
+ bold: textConf.bold,
1165
+ italic: textConf.italic,
1166
+ x: x + explosionX + properties.labelsListRightOffsetx,
1167
+ y: y + explosionY + properties.labelsListRightOffsety,
1168
+ text: labels_right[i][2],
1169
+ valign: 'center',
1170
+ halign: 'left',
1171
+ tag: 'labels',
1172
+ color: labels_right[i][5],
1173
+ cssClass: RGraph.getLabelsCSSClassName({
1174
+ object: this,
1175
+ name: 'labelsClass',
1176
+ index: i
1177
+ })
1178
+ });
1179
+
1180
+ if (ret && ret.node) {
1181
+ ret.node.__index__ = labels_right[i][0];
1182
+ }
1183
+
1184
+ // This draws the stick
1185
+ this.path(
1186
+ 'lc round lw % b m % % qc % % % % s %',
1187
+ properties.labelsSticksLinewidth,
1188
+ labels_right[i][3][0] + explosionX,labels_right[i][3][1] + explosionY,
1189
+ labels_right[i][4][0] + explosionX,labels_right[i][4][1] + explosionY,ret.x - 5 ,ret.y + (ret.height / 2),
1190
+ labels_right[i][5]
1191
+ );
1192
+
1193
+
1194
+ // Draw a circle at the end of the stick
1195
+ this.path(
1196
+ 'b a % % 2 0 6.2830 false, f %',
1197
+ ret.x - 5,ret.y + (ret.height / 2),
1198
+ labels_right[i][5]
1199
+ );
1200
+ }
1201
+ }
1202
+
1203
+
1204
+
1205
+
1206
+
1207
+
1208
+
1209
+
1210
+
1211
+ //
1212
+ // Draw the left hand side labels
1213
+ //
1214
+
1215
+
1216
+
1217
+
1218
+
1219
+ // Calculate how much space there is for each label
1220
+ var vspace_left = (this.canvas.height - properties.marginTop - properties.marginBottom) / labels_left.length
1221
+
1222
+ for (var i=(labels_left.length - 1),y=(properties.marginTop + (vspace_left / 2)); i>=0; y+=vspace_left,i--) {
1223
+
1224
+ if (labels_left[i][2]) {
1225
+
1226
+ var x = this.centerx - this.radius - offset,
1227
+ idx = labels_left[i][0],
1228
+ explosionX = labels_left[i][6][0] ? labels_left[i][6][1] : 0,
1229
+ explosionY = labels_left[i][6][0] ? labels_left[i][6][2] : 0
1230
+
1231
+ var ret = RGraph.text({
1232
+
1233
+ object: this,
1234
+
1235
+ font: textConf.font,
1236
+ size: textConf.size,
1237
+ color: textConf.color,
1238
+ bold: textConf.bold,
1239
+ italic: textConf.italic,
1240
+
1241
+ x: x + explosionX + properties.labelsListLeftOffsetx,
1242
+ y: y + explosionY + properties.labelsListLeftOffsety,
1243
+
1244
+ text: labels_left[i][2],
1245
+ valign: 'center',
1246
+ halign: 'right',
1247
+ tag: 'labels',
1248
+ cssClass: RGraph.getLabelsCSSClassName({
1249
+ object: this,
1250
+ name: 'labelsClass',
1251
+ index: i
1252
+ })
1253
+ });
1254
+
1255
+ if (ret && ret.node) {
1256
+ ret.node.__index__ = labels_left[i][0];
1257
+ }
1258
+
1259
+ this.path(
1260
+ 'lw % b m % % qc % % % % s %',
1261
+ properties.labelsSticksLinewidth,
1262
+ labels_left[i][3][0] + explosionX,labels_left[i][3][1] + explosionY,
1263
+ labels_left[i][4][0] + explosionX,Math.round(labels_left[i][4][1] + explosionY),ret.x + 5 + ret.width,ret.y + (ret.height / 2),
1264
+ labels_left[i][5]
1265
+ );
1266
+
1267
+
1268
+ // Draw a circle at the end of the stick
1269
+ this.path(
1270
+ 'b a % % 2 0 6.2830 false, f %',
1271
+ ret.x + 5 + ret.width,ret.y + (ret.height / 2),
1272
+ labels_left[i][5]
1273
+ );
1274
+ }
1275
+ }
1276
+ };
1277
+
1278
+
1279
+
1280
+
1281
+
1282
+
1283
+
1284
+
1285
+ //
1286
+ // Draw the labelsInside labels if they've been
1287
+ // specified
1288
+ //
1289
+ this.drawLabelsInside = function ()
1290
+ {
1291
+ // Get the text configuration
1292
+ var textConf = RGraph.getTextConf({
1293
+ object: this,
1294
+ prefix: 'labelsInside'
1295
+ });
1296
+
1297
+
1298
+
1299
+
1300
+
1301
+
1302
+
1303
+
1304
+ // If the labelsInsideSpecific is a string (or a number)
1305
+ // then convert it to an array of that string repeated
1306
+ // a number of times (the same number as there are
1307
+ // items in the data)
1308
+ if (RGraph.isTextual(properties.labelsInsideSpecific)) {
1309
+ properties.labelsInsideSpecific = RGraph.arrayFill(
1310
+ [],
1311
+ this.data.length,
1312
+ properties.labelsInsideSpecific
1313
+ );
1314
+ }
1315
+
1316
+
1317
+
1318
+
1319
+
1320
+
1321
+
1322
+ for (let i=0; i<this.data.length; ++i) {
1323
+
1324
+ var centerAngle = this.angles[i][0] + ((this.angles[i][1] - this.angles[i][0]) / 2);
1325
+
1326
+ var p = RGraph.getRadiusEndPoint(
1327
+ this.centerx,
1328
+ this.centery,
1329
+ centerAngle,
1330
+ this.radius - properties.variantDonutWidth - 20 + properties.labelsInsideOffsetr + properties.exploded
1331
+ );
1332
+
1333
+ // Horizontal alignment
1334
+ if (p[0] >= this.centerx) {
1335
+ var halign = 'right';
1336
+ } else {
1337
+ var halign = 'left';
1338
+ }
1339
+
1340
+ // If the labelsInsideSpecific property is set
1341
+ // then use that
1342
+ if (RGraph.isArray(properties.labelsInsideSpecific) && RGraph.isTextual(properties.labelsInsideSpecific[i])) {
1343
+
1344
+ var label = String(properties.labelsInsideSpecific[i]);
1345
+
1346
+ //
1347
+ // Allow for label substitution
1348
+ //
1349
+ label = RGraph.labelSubstitution({
1350
+ object: this,
1351
+ text: label,
1352
+ index: i,
1353
+ value: this.data[i],
1354
+ decimals: properties.labelsInsideSpecificFormattedDecimals || 0,
1355
+ unitsPre: properties.labelsInsideSpecificFormattedUnitsPre || '',
1356
+ unitsPost: properties.labelsInsideSpecificFormattedUnitsPost || '',
1357
+ thousand: properties.labelsInsideSpecificFormattedThousand || ',',
1358
+ point: properties.labelsInsideSpecificFormattedPoint || '.'
1359
+ });
1360
+
1361
+
1362
+
1363
+ } else {
1364
+
1365
+ var label = RGraph.numberFormat({
1366
+ object: this,
1367
+ number: this.data[i].toFixed(properties.labelsInsideDecimals),
1368
+ unitspre: properties.labelsInsideUnitsPre,
1369
+ unitspost: properties.labelsInsideUnitsPost,
1370
+ point: properties.labelsInsidePoint,
1371
+ thousand: properties.labelsInsideThousand
1372
+ });
1373
+ }
1374
+
1375
+
1376
+ RGraph.text({
1377
+ object: this,
1378
+ x: p[0],
1379
+ y: p[1],
1380
+ text: label,
1381
+ size: textConf.size,
1382
+ font: textConf.font,
1383
+ color: textConf.color,
1384
+ bold: textConf.bold,
1385
+ italic: textConf.italic,
1386
+ halign: properties.labelsInsideHalign === 'center' ? 'center' : halign,
1387
+ valign: 'center',
1388
+ bounding: properties.labelsInsideBounding,
1389
+ boundingFill: properties.labelsInsideBoundingFill,
1390
+ boundingStroke: properties.labelsInsideBoundingStroke
1391
+ });
1392
+ }
1393
+ }
1394
+
1395
+
1396
+
1397
+
1398
+
1399
+
1400
+
1401
+
1402
+ //
1403
+ // This function draws the pie chart sticks (for the labels)
1404
+ //
1405
+ this.drawSticks = function ()
1406
+ {
1407
+ var offset = properties.linewidth / 2,
1408
+ exploded = properties.exploded,
1409
+ sticks = properties.labelsSticks,
1410
+ colors = properties.colors,
1411
+ cx = this.centerx,
1412
+ cy = this.centery,
1413
+ radius = this.radius,
1414
+ points = [],
1415
+ linewidth = properties.labelsSticksLinewidth
1416
+
1417
+ for (var i=0,len=this.angles.length; i<len; ++i) {
1418
+
1419
+ if (!this.properties.labels[i]) {
1420
+ continue;
1421
+ }
1422
+
1423
+ var segment = this.angles[i];
1424
+
1425
+ // This allows the labelsSticks to be an array as well as a boolean
1426
+ if (typeof sticks === 'object' && !sticks[i]) {
1427
+ continue;
1428
+ }
1429
+
1430
+ var radians = segment[1] - segment[0];
1431
+
1432
+ this.context.beginPath();
1433
+ this.context.strokeStyle = typeof properties.labelsSticksColors === 'string' ? properties.labelsSticksColors : (!RGraph.isNull(properties.labelsSticksColors) ? properties.labelsSticksColors[i] : 'gray');
1434
+ this.context.lineWidth = linewidth;
1435
+
1436
+ if (typeof properties.labelsSticksColor === 'string') {
1437
+ this.context.strokeStyle = properties.labelsSticksColor;
1438
+ }
1439
+
1440
+ var midpoint = (segment[0] + (radians / 2));
1441
+
1442
+ if (typeof exploded === 'object' && exploded[i]) {
1443
+ var extra = exploded[i];
1444
+ } else if (typeof exploded === 'number') {
1445
+ var extra = exploded;
1446
+ } else {
1447
+ var extra = 0;
1448
+ }
1449
+
1450
+ //
1451
+ // Determine the stick length
1452
+ //
1453
+ var stickLength = typeof properties.labelsSticksLength === 'object' ? properties.labelsSticksLength[i] : properties.labelsSticksLength;
1454
+
1455
+
1456
+ points[0] = RGraph.getRadiusEndPoint(cx, cy, midpoint, radius + extra + offset);
1457
+ points[1] = RGraph.getRadiusEndPoint(cx, cy, midpoint, radius + stickLength + extra - 5);
1458
+
1459
+ points[2] = RGraph.getRadiusEndPoint(cx, cy, midpoint, radius + stickLength + extra + properties.labelsRadiusOffset);
1460
+
1461
+ points[3] = RGraph.getRadiusEndPoint(cx, cy, midpoint, radius + stickLength + extra + properties.labelsRadiusOffset);
1462
+ points[3][0] += (points[3][0] > cx ? 5 : -5);
1463
+
1464
+ points[4] = [
1465
+ points[2][0] + (points[2][0] > cx ? 5 + properties.labelsSticksHlength : -5 - properties.labelsSticksHlength),
1466
+ points[2][1]
1467
+ ];
1468
+
1469
+
1470
+ this.context.moveTo(points[0][0], points[0][1]);
1471
+ this.context.quadraticCurveTo(
1472
+ points[2][0],
1473
+ points[2][1],
1474
+ points[4][0],
1475
+ points[4][1]
1476
+ );
1477
+
1478
+ this.context.stroke();
1479
+
1480
+ //
1481
+ // Save the stick end coords
1482
+ //
1483
+ this.coordsSticks[i] = [
1484
+ points[0],
1485
+ points[1],
1486
+ points[2],
1487
+ points[3],
1488
+ points[4]
1489
+ ];
1490
+ }
1491
+ };
1492
+
1493
+
1494
+
1495
+
1496
+
1497
+
1498
+
1499
+
1500
+ //
1501
+ // The (now Pie chart specific) getSegment function
1502
+ //
1503
+ // @param object e The event object
1504
+ //
1505
+ this.getShape = function (e)
1506
+ {
1507
+ // The optional arg provides a way of allowing some accuracy (pixels)
1508
+ var accuracy = arguments[1] ? arguments[1] : 0;
1509
+
1510
+ var canvas = this.canvas;
1511
+ var context = this.context;
1512
+ var mouseCoords = RGraph.getMouseXY(e);
1513
+ var mouseX = mouseCoords[0];
1514
+ var mouseY = mouseCoords[1];
1515
+ var r = this.radius;
1516
+ var angles = this.angles;
1517
+
1518
+ for (var i=0,len=angles.length; i<len; ++i) {
1519
+
1520
+ if (RGraph.tooltipsHotspotIgnore(this, i)) {
1521
+ continue;
1522
+ }
1523
+
1524
+ // Draw the segment again so that it can be tested
1525
+ this.path(
1526
+ 'b ss rgba(0,0,0,0) a % % % % % false',
1527
+ angles[i][2],angles[i][3],this.radius,angles[i][0],angles[i][1]
1528
+ );
1529
+
1530
+ if (this.type === 'pie' && properties.variant.indexOf('donut') !== -1) {
1531
+ this.path(
1532
+ 'a % % % % % true',
1533
+ angles[i][2],angles[i][3],(typeof properties.variantDonutWidth == 'number' ? this.radius - properties.variantDonutWidth : this.radius / 2),angles[i][1],angles[i][0]
1534
+ );
1535
+ } else {
1536
+ this.path(
1537
+ 'l % %',
1538
+ angles[i][2],angles[i][3]
1539
+ );
1540
+ }
1541
+
1542
+ this.path('c');
1543
+
1544
+ if (!this.context.isPointInPath(mouseX, mouseY)) {
1545
+ continue;
1546
+ }
1547
+
1548
+ if (angles[i][0] < 0) angles[i][0] += RGraph.TWOPI;
1549
+ if (angles[i][1] > RGraph.TWOPI) angles[i][1] -= RGraph.TWOPI;
1550
+
1551
+ //
1552
+ // Get the tooltip for the returned shape
1553
+ //
1554
+ if (RGraph.parseTooltipText && properties.tooltips) {
1555
+ var tooltip = RGraph.parseTooltipText(properties.tooltips, i);
1556
+ }
1557
+
1558
+ return {
1559
+ object: this,
1560
+ x: angles[i][2],
1561
+ y: angles[i][3],
1562
+ radius: this.radius,
1563
+ angleStart: angles[i][0],
1564
+ angleEnd: angles[i][1],
1565
+ index: i,
1566
+ dataset: 0,
1567
+ sequentialIndex: i,
1568
+ label: properties.labels && typeof properties.labels[i] === 'string' ? properties.labels[i] : null,
1569
+ tooltip: typeof tooltip === 'string' ? tooltip : null
1570
+ };
1571
+ }
1572
+
1573
+ return null;
1574
+ };
1575
+
1576
+
1577
+
1578
+
1579
+
1580
+
1581
+
1582
+
1583
+ //
1584
+ // Draw the borders for the Pie chart
1585
+ //
1586
+ this.drawBorders = function ()
1587
+ {
1588
+ if (properties.linewidth > 0) {
1589
+
1590
+ this.context.lineWidth = properties.linewidth;
1591
+ this.context.strokeStyle = properties.colorsStroke;
1592
+
1593
+ var r = this.radius;
1594
+
1595
+ for (var i=0,len=this.angles.length; i<len; ++i) {
1596
+
1597
+ var segment = this.angles[i];
1598
+
1599
+ this.context.beginPath();
1600
+ this.context.arc(segment[2],
1601
+ segment[3],
1602
+ r,
1603
+ (segment[0]),
1604
+ (segment[0] + 0.001),
1605
+ 0);
1606
+ this.context.arc(segment[2],
1607
+ segment[3],
1608
+ properties.variant == 'donut' ? (typeof properties.variantDonutWidth == 'number' ? this.radius - properties.variantDonutWidth : r / 2): r,
1609
+ segment[0],
1610
+ segment[0] + 0.0001,
1611
+ 0);
1612
+ this.context.closePath();
1613
+ this.context.stroke();
1614
+ }
1615
+ }
1616
+ };
1617
+
1618
+
1619
+
1620
+
1621
+
1622
+
1623
+
1624
+
1625
+ //
1626
+ // Returns the radius of the pie chart
1627
+ //
1628
+ // [06-02-2012] Maintained for compatibility ONLY.
1629
+ //
1630
+ this.getRadius = function ()
1631
+ {
1632
+ this.graph = {
1633
+ width: this.canvas.width - properties.marginLeft - properties.marginRight,
1634
+ height: this.canvas.height - properties.marginTop - properties.marginBottom
1635
+ };
1636
+
1637
+ if (typeof properties.radius == 'number') {
1638
+ this.radius = properties.radius;
1639
+ } else {
1640
+ this.radius = Math.min(this.graph.width, this.graph.height) / 2;
1641
+ }
1642
+
1643
+ // If the radius property is a string treat it
1644
+ // as an adjustment
1645
+ if (typeof properties.radius === 'string') {
1646
+ this.radius = this.radius + parseFloat(properties.radius);
1647
+ }
1648
+
1649
+ return this.radius;
1650
+ };
1651
+
1652
+
1653
+
1654
+
1655
+
1656
+
1657
+
1658
+
1659
+ //
1660
+ // A programmatic explode function
1661
+ //
1662
+ // @param object obj The chart object
1663
+ // @param number index The zero-indexed number of the segment
1664
+ // @param number size The size (in pixels) of the explosion
1665
+ //
1666
+ this.explodeSegment = function (index, size,callback = null)
1667
+ {
1668
+ if (typeof this.exploding === 'number' && this.exploding === index) {
1669
+ return;
1670
+ }
1671
+
1672
+ //this.set('exploded', []);
1673
+ if (!properties.exploded) {
1674
+ properties.exploded = [];
1675
+ }
1676
+
1677
+ // If exploded is a number - convert it to an array
1678
+ if (typeof properties.exploded === 'number') {
1679
+
1680
+ var original_explode = properties.exploded;
1681
+ var exploded = properties.exploded;
1682
+
1683
+ properties.exploded = [];
1684
+
1685
+ for (var i=0,len=this.data.length; i<len; ++i) {
1686
+ properties.exploded[i] = exploded;
1687
+ }
1688
+ }
1689
+
1690
+ properties.exploded[index] = typeof original_explode == 'number' ? original_explode : 0;
1691
+
1692
+ this.exploding = index;
1693
+ var delay = RGraph.ISIE && !RGraph.ISIE10 ? 25 : 16.666;
1694
+ var obj = this;
1695
+
1696
+ for (var o=0; o<size; ++o) {
1697
+
1698
+ setTimeout(
1699
+ function ()
1700
+ {
1701
+
1702
+ properties.exploded[index] += 1;
1703
+ RGraph.clear(obj.canvas);
1704
+ RGraph.redrawCanvas(obj.canvas);
1705
+ }, o * delay);
1706
+ }
1707
+
1708
+ var obj = this;
1709
+ setTimeout(function ()
1710
+ {
1711
+ obj.exploding = null;
1712
+
1713
+ if (RGraph.isFunction (callback)) {
1714
+ callback(obj);
1715
+ }
1716
+
1717
+ }, size * delay);
1718
+ };
1719
+
1720
+
1721
+
1722
+
1723
+
1724
+
1725
+
1726
+
1727
+ //
1728
+ // This function highlights a segment
1729
+ //
1730
+ // @param array segment The segment information that is returned by the pie.getSegment(e) function
1731
+ //
1732
+ this.highlight_segment = function (segment)
1733
+ {
1734
+ this.context.beginPath();
1735
+ this.context.strokeStyle = properties.highlightStyleTwodStroke;
1736
+ this.context.fillStyle = properties.highlightStyleTwodFill;
1737
+ this.context.moveTo(segment[0], segment[1]);
1738
+ this.context.arc(segment[0], segment[1], segment[2], this.angles[segment[5]][0], this.angles[segment[5]][1], 0);
1739
+ this.context.lineTo(segment[0], segment[1]);
1740
+ this.context.closePath();
1741
+
1742
+ this.context.stroke();
1743
+ this.context.fill();
1744
+ };
1745
+
1746
+
1747
+
1748
+
1749
+
1750
+
1751
+
1752
+
1753
+ //
1754
+ // Each object type has its own Highlight() function which highlights
1755
+ // the appropriate shape
1756
+ //
1757
+ // @param object shape The shape to highlight
1758
+ //
1759
+ this.highlight = function (shape)
1760
+ {
1761
+ if (properties.tooltipsHighlight) {
1762
+
1763
+ if (typeof properties.highlightStyle === 'function') {
1764
+ (properties.highlightStyle)(shape);
1765
+
1766
+
1767
+
1768
+
1769
+
1770
+
1771
+
1772
+
1773
+
1774
+ //
1775
+ // Inverted style of highlighting
1776
+ //
1777
+ } else if (properties.highlightStyle === 'invert') {
1778
+
1779
+ // Loop through all of the segments
1780
+ for (var i=0; i<this.angles.length; ++i) {
1781
+
1782
+ if (i !== shape.index) {
1783
+ this.path(
1784
+ 'b lw % m % % a % % % % % false c s % f %',
1785
+ properties.highlightStyleTwodLinewidth,
1786
+ this.angles[i][2], this.angles[i][3],
1787
+ this.angles[i][2], this.angles[i][3],shape.radius, this.angles[i][0], this.angles[i][1],
1788
+ properties.highlightStyleTwodStroke,
1789
+ properties.highlightStyleTwodFill
1790
+ );
1791
+ }
1792
+ }
1793
+
1794
+ //this.context.beginPath();
1795
+
1796
+ // this.context.strokeStyle = properties.highlightStyleTwodStroke;
1797
+ // this.context.fillStyle = properties.highlightStyleTwodFill;
1798
+
1799
+ // if (properties.variant.indexOf('donut') > -1) {
1800
+ // this.context.arc(shape.x, shape.y, shape.radius, shape.angleStart, shape.angleEnd, false);
1801
+ // this.context.arc(shape.x, shape.y, typeof properties.variantDonutWidth == 'number' ? this.radius - properties.variantDonutWidth : shape.radius / 2, shape.angleEnd, shape.angleStart, true);
1802
+ // } else {
1803
+ // this.context.arc(shape.x, shape.y, shape.radius + 1, shape.angleStart, shape.angleEnd, false);
1804
+ // this.context.lineTo(shape.x, shape.y);
1805
+ // }
1806
+ //this.context.closePath();
1807
+
1808
+ //this.context.stroke();
1809
+ //this.context.fill();
1810
+
1811
+
1812
+
1813
+
1814
+
1815
+
1816
+
1817
+
1818
+
1819
+
1820
+
1821
+
1822
+
1823
+
1824
+ //
1825
+ // 3D style of highlighting
1826
+ //
1827
+ } else if (properties.highlightStyle == '3d') {
1828
+
1829
+ this.context.lineWidth = 1;
1830
+
1831
+ // This is the extent of the 2D effect. Bigger values will give the appearance of a larger "protusion"
1832
+ var extent = 2;
1833
+
1834
+ // Draw a white-out where the segment is
1835
+ this.context.beginPath();
1836
+ RGraph.noShadow(this);
1837
+ this.context.fillStyle = 'rgba(0,0,0,0)';
1838
+ this.context.arc(shape.x, shape.y, shape.radius, shape.angleStart, shape.angleEnd, false);
1839
+ if (properties.variant == 'donut') {
1840
+ this.context.arc(shape.x, shape.y, shape.radius / 5, shape.angleEnd, shape.angleStart, true);
1841
+ } else {
1842
+ this.context.lineTo(shape.x, shape.y);
1843
+ }
1844
+ this.context.closePath();
1845
+ this.context.fill();
1846
+
1847
+ // Draw the new segment
1848
+ this.context.beginPath();
1849
+
1850
+ this.context.shadowColor = '#666';
1851
+ this.context.shadowBlur = 3;
1852
+ this.context.shadowOffsetX = 3;
1853
+ this.context.shadowOffsetY = 3;
1854
+
1855
+ this.context.fillStyle = properties.colors[shape.index];
1856
+ this.context.strokeStyle = properties.colorsStroke;
1857
+ this.context.arc(shape.x - extent, shape.y - extent, shape.radius, shape.angleStart, shape.angleEnd, false);
1858
+ if (properties.variant == 'donut') {
1859
+ this.context.arc(shape.x - extent, shape.y - extent, shape.radius / 2, shape.angleEnd, shape.angleStart, true)
1860
+ } else {
1861
+ this.context.lineTo(shape.x - extent, shape.y - extent);
1862
+ }
1863
+ this.context.closePath();
1864
+
1865
+ this.context.stroke();
1866
+ this.context.fill();
1867
+
1868
+ // Turn off the shadow
1869
+ RGraph.noShadow(this);
1870
+
1871
+ //
1872
+ // If a border is defined, redraw that
1873
+ //
1874
+ if (properties.border) {
1875
+ this.context.beginPath();
1876
+ this.context.strokeStyle = properties.borderColor;
1877
+ this.context.lineWidth = 5;
1878
+ this.context.arc(shape.x - extent, shape.y - extent, shape.radius - 2, shape.angleStart, shape.angleEnd, false);
1879
+ this.context.stroke();
1880
+ }
1881
+
1882
+
1883
+
1884
+
1885
+ // Outline style of highlighting
1886
+ } else if (properties.highlightStyle === 'outline') {
1887
+
1888
+ var index = shape.index,
1889
+ coords = this.angles[index],
1890
+ color = this.get('colors')[index]
1891
+ width = this.radius / 12.5;
1892
+
1893
+ // Allow custom setting of outline
1894
+ if (typeof properties.highlightStyleOutlineWidth === 'number') {
1895
+ width = properties.highlightStyleOutlineWidth;
1896
+ }
1897
+
1898
+
1899
+
1900
+ this.path(
1901
+ 'ga 0.25 b a % % % % % false a % % % % % true c f % ga 1',
1902
+ coords[2],
1903
+ coords[3],
1904
+ this.radius + 2 + width,
1905
+ coords[0],
1906
+ coords[1],
1907
+
1908
+ coords[2],
1909
+ coords[3],
1910
+ this.radius + 2,
1911
+ coords[1],
1912
+ coords[0],
1913
+ color
1914
+ );
1915
+
1916
+
1917
+
1918
+
1919
+
1920
+
1921
+ // Default 2D style of highlighting
1922
+ } else {
1923
+
1924
+ this.path(
1925
+ 'b ss % fs % lw %',
1926
+ properties.highlightStyleTwodStroke,
1927
+ properties.highlightStyleTwodFill,
1928
+ properties.highlightStyleTwodLinewidth
1929
+ );
1930
+
1931
+
1932
+ if (properties.variant.indexOf('donut') > -1) {
1933
+ this.context.arc(shape.x, shape.y, shape.radius, shape.angleStart, shape.angleEnd, false);
1934
+ this.context.arc(shape.x, shape.y, typeof properties.variantDonutWidth == 'number' ? this.radius - properties.variantDonutWidth : shape.radius / 2, shape.angleEnd, shape.angleStart, true);
1935
+ } else {
1936
+ this.context.arc(shape.x, shape.y, shape.radius + 1, shape.angleStart, shape.angleEnd, false);
1937
+ this.context.lineTo(shape.x, shape.y);
1938
+ }
1939
+ this.context.closePath();
1940
+
1941
+ this.context.stroke();
1942
+ this.context.fill();
1943
+ }
1944
+ }
1945
+ };
1946
+
1947
+
1948
+
1949
+
1950
+
1951
+
1952
+
1953
+
1954
+ //
1955
+ // The getObjectByXY() worker method. The Pie chart is able to use the
1956
+ // getShape() method - so it does.
1957
+ //
1958
+ this.getObjectByXY = function (e)
1959
+ {
1960
+ if (this.getShape(e)) {
1961
+ return this;
1962
+ }
1963
+ };
1964
+
1965
+
1966
+
1967
+
1968
+
1969
+
1970
+
1971
+
1972
+ //
1973
+ // Draws the centerpin if requested
1974
+ //
1975
+ this.drawCenterpin = function ()
1976
+ {
1977
+ if (typeof properties.centerpin === 'number' && properties.centerpin > 0) {
1978
+
1979
+ var cx = this.centerx;
1980
+ var cy = this.centery;
1981
+
1982
+ this.context.beginPath();
1983
+ this.context.strokeStyle = properties.centerpinStroke ? properties.centerpinStroke : properties.colorsStroke;
1984
+ this.context.fillStyle = properties.centerpinFill ? properties.centerpinFill : properties.colorsStroke;
1985
+ this.context.moveTo(cx, cy);
1986
+ this.context.arc(cx, cy, properties.centerpin, 0, RGraph.TWOPI, false);
1987
+ this.context.stroke();
1988
+ this.context.fill();
1989
+ }
1990
+ };
1991
+
1992
+
1993
+
1994
+
1995
+
1996
+
1997
+
1998
+
1999
+ //
2000
+ // This draws Ingraph labels
2001
+ //
2002
+ this.drawLabelsIngraph =
2003
+ this.drawInGraphLabels = function ()
2004
+ {
2005
+ var context = this.context;
2006
+ var cx = this.centerx;
2007
+ var cy = this.centery;
2008
+ var radius = properties.labelsIngraphRadius;
2009
+
2010
+ // If the labelsIngraphSpecific property is a string
2011
+ // make it an array and populate it
2012
+ if (typeof properties.labelsIngraphSpecific === 'string') {
2013
+ properties.labelsIngraphSpecific = RGraph.arrayFill(
2014
+ [],
2015
+ this.data.length,
2016
+ properties.labelsIngraphSpecific
2017
+ );
2018
+ }
2019
+
2020
+ // Reset this to an empty array
2021
+ this.set('labelsIngraphUndrawn', []);
2022
+
2023
+ // Account for offsetting
2024
+ if (RGraph.isNumber(properties.labelsIngraphRadiusOffset)) {
2025
+ var radiusOffset = properties.labelsIngraphRadiusOffset;
2026
+ } else {
2027
+ var radiusOffset = 0;
2028
+ }
2029
+
2030
+ //
2031
+ // Is the radius less than 2? If so then it's a
2032
+ // factor and not an exact point
2033
+ //
2034
+ if (radius <= 2 && radius > 0) {
2035
+ radiusFactor = radius;
2036
+ } else {
2037
+ radiusFactor = 0.5;
2038
+ }
2039
+
2040
+ if (properties.variant === 'donut') {
2041
+ var r = this.radius * (0.5 + (radiusFactor * 0.5));
2042
+
2043
+ if (typeof properties.variantDonutWidth == 'number') {
2044
+ var r = (this.radius - properties.variantDonutWidth) + (properties.variantDonutWidth / 2);
2045
+ }
2046
+ } else {
2047
+ var r = this.radius * radiusFactor;
2048
+ }
2049
+
2050
+ if (radius > 2) {
2051
+ r = radius;
2052
+ }
2053
+
2054
+ for (var i=0,len=this.angles.length; i<len; ++i) {
2055
+
2056
+ // This handles any explosion that the segment may have
2057
+ if (typeof properties.exploded == 'object' && typeof properties.exploded[i] == 'number') {
2058
+ var explosion = properties.exploded[i];
2059
+ } else if (typeof properties.exploded == 'number') {
2060
+ var explosion = parseInt(properties.exploded);
2061
+ } else {
2062
+ var explosion = 0;
2063
+ }
2064
+
2065
+ var angleStart = this.angles[i][0];
2066
+ var angleEnd = this.angles[i][1];
2067
+ var angleCenter = ((angleEnd - angleStart) / 2) + angleStart;
2068
+ var coords = RGraph.getRadiusEndPoint(
2069
+ this.centerx,
2070
+ this.centery,
2071
+ angleCenter,
2072
+ r + (explosion ? explosion : 0) + (properties.labelsIngraphRadiusOffset || 0)
2073
+ );
2074
+
2075
+ var x = coords[0];
2076
+ var y = coords[1];
2077
+
2078
+ // Work out the text of the label:
2079
+ //
2080
+ // Use specific text
2081
+ if (properties.labelsIngraphSpecific && typeof properties.labelsIngraphSpecific[i] === 'string') {
2082
+
2083
+ var text = RGraph.labelSubstitution({
2084
+ object: this,
2085
+ text: properties.labelsIngraphSpecific[i],
2086
+ index: i,
2087
+ value: this.data[i],
2088
+ decimals: properties.labelsIngraphSpecificFormattedDecimals || 0,
2089
+ unitsPre: properties.labelsIngraphSpecificFormattedUnitsPre || '',
2090
+ unitsPost: properties.labelsIngraphSpecificFormattedUnitsPost || '',
2091
+ thousand: properties.labelsIngraphSpecificFormattedThousand || ',',
2092
+ point: properties.labelsIngraphSpecificFormattedPoint || '.'
2093
+ });
2094
+
2095
+
2096
+
2097
+
2098
+
2099
+ // Use the value
2100
+ } else if (RGraph.isNumber(this.data[i]) ) {
2101
+
2102
+ var text = RGraph.numberFormat({
2103
+ object: this,
2104
+ number: this.data[i].toFixed(properties.labelsIngraphDecimals),
2105
+ unitspre: properties.labelsIngraphUnitsPre,
2106
+ unitspost: properties.labelsIngraphUnitsPost,
2107
+ point: properties.labelsIngraphPoint,
2108
+ thousand: properties.labelsIngraphThousand
2109
+ });
2110
+ }
2111
+
2112
+ if (text) {
2113
+
2114
+ this.context.beginPath();
2115
+
2116
+ var textConf = RGraph.getTextConf({
2117
+ object: this,
2118
+ prefix: 'labelsIngraph'
2119
+ });
2120
+
2121
+
2122
+
2123
+
2124
+
2125
+
2126
+
2127
+
2128
+
2129
+
2130
+
2131
+
2132
+ /////////////////////////////////////////////
2133
+ // //
2134
+ // Determine if the text will fit into the //
2135
+ // segment //
2136
+ // //
2137
+ /////////////////////////////////////////////
2138
+ var ret = RGraph.text({
2139
+ object: this,
2140
+ font: textConf.font,
2141
+ size: textConf.size,
2142
+ color: 'transparent', //
2143
+ bold: textConf.bold,
2144
+ italic: textConf.italic,
2145
+ x: x,
2146
+ y: y,
2147
+ text: text,
2148
+ valign: 'center',
2149
+ halign: 'center',
2150
+ bounding: false
2151
+ });
2152
+
2153
+ this.context.stroke();
2154
+
2155
+
2156
+ this.path(
2157
+ 'b lw 1 m % % a % % % % % false',
2158
+
2159
+ this.centerx,
2160
+ this.centery,
2161
+
2162
+ this.centerx,
2163
+ this.centery,
2164
+ this.radius + 10,
2165
+ this.angles[i][0],
2166
+ this.angles[i][1]
2167
+ );
2168
+
2169
+ // Account for this being a donut chart
2170
+ if (this.properties.variant.indexOf('donut') >= 0) {
2171
+
2172
+ this.path(
2173
+ 'a % % % % % true',
2174
+ this.centerx,
2175
+ this.centery,
2176
+ this.radius - (this.properties.variantDonutWidth || this.radius / 2),
2177
+ this.angles[i][1],
2178
+ this.angles[i][0]
2179
+ );
2180
+ }
2181
+
2182
+ let [textX, textY, textW, textH] = [ret.x, ret.y, ret.width, ret.height];
2183
+
2184
+ if (
2185
+ this.properties.labelsIngraphUndrawnAlwaysShow === false &&
2186
+ (
2187
+ !this.context.isPointInPath(textX, textY) ||
2188
+ !this.context.isPointInPath(textX + textW, textY) ||
2189
+ !this.context.isPointInPath(textX, textY + textH) ||
2190
+ !this.context.isPointInPath(textX + textW, textY + textH)
2191
+ )
2192
+ ) {
2193
+
2194
+ // This clears any existing path
2195
+ this.context.beginPath();
2196
+
2197
+ var undrawn = {
2198
+ index: i,
2199
+ text: text
2200
+ };
2201
+
2202
+ this.get('labelsIngraphUndrawn').push(undrawn);
2203
+
2204
+ // If undrawn ingraph labels are wanted to
2205
+ // be set as labels instead - add this text
2206
+ // to the Pie chart labels property
2207
+ if (properties.labelsIngraphUndrawn && properties.labelsIngraphUndrawnAsLabels) {
2208
+
2209
+ if (!RGraph.isArray(this.properties.labels)) {
2210
+ this.properties.labels = [];
2211
+ }
2212
+
2213
+ this.properties.labels[undrawn.index] = undrawn.text;
2214
+
2215
+ if (!RGraph.Registry.get('pie-chart-ingraphlabels-redraw-function-added')) {
2216
+ var id = RGraph.addCustomEventListener(this, 'draw', function (obj)
2217
+ {
2218
+ // Now that we're in the
2219
+ // function that runs to
2220
+ // reenable the labelsingraph
2221
+ // labels - remove it
2222
+ RGraph.removeCustomEventListener(
2223
+ obj,
2224
+ RGraph.Registry.get('pie-chart-ingraphlabels-redraw-function-added')
2225
+ );
2226
+
2227
+ // Redraw the canvas - but only
2228
+ // once
2229
+ RGraph.runOnce('pie-chart-ingraphlabels-redraw-function', function ()
2230
+ {
2231
+ RGraph.redraw();
2232
+ });
2233
+ });
2234
+
2235
+ RGraph.Registry.set('pie-chart-ingraphlabels-redraw-function-added', id);
2236
+ }
2237
+ }
2238
+
2239
+ continue;
2240
+ }
2241
+
2242
+ // This clears any existing path
2243
+ this.context.beginPath();
2244
+
2245
+ //////////////////////////////////////////////////////////////////
2246
+
2247
+
2248
+
2249
+
2250
+
2251
+
2252
+
2253
+
2254
+
2255
+
2256
+
2257
+
2258
+
2259
+
2260
+
2261
+
2262
+ var ret = RGraph.text({
2263
+ object: this,
2264
+ font: textConf.font,
2265
+ size: textConf.size,
2266
+ color: textConf.color,
2267
+ bold: textConf.bold,
2268
+ italic: textConf.italic,
2269
+ x: x,
2270
+ y: y,
2271
+ text: text,
2272
+ valign: 'center',
2273
+ halign: 'center',
2274
+ bounding: properties.labelsIngraphBounding,
2275
+ boundingFill: properties.labelsIngraphBoundingFill,
2276
+ boundingStroke: properties.labelsIngraphBoundingStroke,
2277
+ tag: 'labels.ingraph'
2278
+ });
2279
+ this.context.stroke();
2280
+ }
2281
+ }
2282
+ };
2283
+
2284
+
2285
+
2286
+
2287
+
2288
+
2289
+
2290
+
2291
+ //
2292
+ // Draws the center label if required
2293
+ //
2294
+ this.drawCenterLabel = function (label)
2295
+ {
2296
+ var textConf = RGraph.getTextConf({
2297
+ object: this,
2298
+ prefix: 'labelsCenter'
2299
+ });
2300
+
2301
+ RGraph.text({
2302
+
2303
+ object: this,
2304
+
2305
+ font: textConf.font,
2306
+ size: textConf.size,
2307
+ color: textConf.color,
2308
+ bold: textConf.bold,
2309
+ italic: textConf.italic,
2310
+
2311
+ x: this.centerx + properties.labelsCenterOffsetx,
2312
+ y: this.centery + properties.labelsCenterOffsety,
2313
+
2314
+ halign: 'center',
2315
+ valign: 'center',
2316
+
2317
+ text: label,
2318
+
2319
+ bounding: true,
2320
+ boundingFill: 'rgba(255,255,255,0.7)',
2321
+ boundingStroke: 'rgba(0,0,0,0)',
2322
+
2323
+ tag: 'labels.center'
2324
+ });
2325
+ };
2326
+
2327
+
2328
+
2329
+
2330
+
2331
+
2332
+
2333
+
2334
+ //
2335
+ // This returns the angle for a value based around the maximum number
2336
+ //
2337
+ // @param number value The value to get the angle for
2338
+ //
2339
+ this.getAngle = function (value)
2340
+ {
2341
+ if (value > this.total) {
2342
+ return null;
2343
+ }
2344
+
2345
+ var angle = (value / this.total) * RGraph.TWOPI;
2346
+
2347
+ // Handle the origin (it can br -HALFPI or 0)
2348
+ angle += properties.origin;
2349
+
2350
+ return angle;
2351
+ };
2352
+
2353
+
2354
+
2355
+
2356
+
2357
+
2358
+
2359
+
2360
+ //
2361
+ // This allows for easy specification of gradients
2362
+ //
2363
+ this.parseColors = function ()
2364
+ {
2365
+ // Save the original colors so that they can be restored when the canvas is reset
2366
+ if (this.original_colors.length === 0) {
2367
+ this.original_colors.colors = RGraph.arrayClone(properties.colors);
2368
+ this.original_colors.keyColors = RGraph.arrayClone(properties.keyColors);
2369
+ this.original_colors.colorsStroke = RGraph.arrayClone(properties.colorsStroke);
2370
+ this.original_colors.highlightStroke = RGraph.arrayClone(properties.highlightStroke);
2371
+ this.original_colors.highlightStyleTwodFill = RGraph.arrayClone(properties.highlightStyleTwodFill);
2372
+ this.original_colors.highlightStyleTwodStroke = RGraph.arrayClone(properties.highlightStyleTwodStroke);
2373
+ this.original_colors.labelsIngraphBoundingFill = RGraph.arrayClone(properties.labelsIngraphBoundingFill);
2374
+ this.original_colors.labelsIngraphColor = RGraph.arrayClone(properties.labelsIngraphColor);
2375
+ }
2376
+
2377
+ for (var i=0; i<properties.colors.length; ++i) {
2378
+ properties.colors[i] = this.parseSingleColorForGradient(properties.colors[i]);
2379
+ }
2380
+
2381
+ var keyColors = properties.keyColors;
2382
+ if (keyColors) {
2383
+ for (var i=0; i<keyColors.length; ++i) {
2384
+ keyColors[i] = this.parseSingleColorForGradient(keyColors[i]);
2385
+ }
2386
+ }
2387
+
2388
+ properties.colorsStroke = this.parseSingleColorForGradient(properties.colorsStroke);
2389
+ properties.highlightStroke = this.parseSingleColorForGradient(properties.highlightStroke);
2390
+ properties.highlightStyleTwodFill = this.parseSingleColorForGradient(properties.highlightStyleTwodFill);
2391
+ properties.highlightStyleTwodStroke = this.parseSingleColorForGradient(properties.highlightStyleTwodStroke);
2392
+ properties.labelsIngraphBoundingFill = this.parseSingleColorForGradient(properties.labelsIngraphBoundingFill);
2393
+ properties.labelsIngraphColor = this.parseSingleColorForGradient(properties.labelsIngraphColor);
2394
+ };
2395
+
2396
+
2397
+
2398
+
2399
+
2400
+
2401
+
2402
+
2403
+ //
2404
+ // Use this function to reset the object to the post-constructor state. Eg reset colors if
2405
+ // need be etc
2406
+ //
2407
+ this.reset = function ()
2408
+ {
2409
+ };
2410
+
2411
+
2412
+
2413
+
2414
+
2415
+
2416
+
2417
+
2418
+ //
2419
+ // This parses a single color value
2420
+ //
2421
+ this.parseSingleColorForGradient = function (color)
2422
+ {
2423
+ if (!color || typeof color != 'string') {
2424
+ return color;
2425
+ }
2426
+
2427
+ if (color.match(/^gradient\((.*)\)$/i)) {
2428
+
2429
+ // Allow for JSON gradients
2430
+ if (color.match(/^gradient\(({.*})\)$/i)) {
2431
+ return RGraph.parseJSONGradient({object: this, def: RegExp.$1});
2432
+ }
2433
+
2434
+ var parts = RegExp.$1.split(':');
2435
+
2436
+ // If the chart is a donut - the first width should half the total radius
2437
+ if (properties.variant == 'donut') {
2438
+ var radius_start = typeof properties.variantDonutWidth == 'number' ? this.radius - properties.variantDonutWidth : this.radius / 2;
2439
+ } else {
2440
+ var radius_start = 0;
2441
+ }
2442
+
2443
+ // Create the gradient
2444
+ var grad = this.context.createRadialGradient(
2445
+ this.centerx,
2446
+ this.centery,
2447
+ radius_start,
2448
+ this.centerx,
2449
+ this.centery,
2450
+ Math.min(this.canvas.width - properties.marginLeft - properties.marginRight,
2451
+ this.canvas.height - properties.marginTop - properties.marginBottom) / 2
2452
+ );
2453
+
2454
+
2455
+ var diff = 1 / (parts.length - 1);
2456
+
2457
+ grad.addColorStop(0, RGraph.trim(parts[0]));
2458
+
2459
+ for (var j=1; j<parts.length; ++j) {
2460
+ grad.addColorStop(j * diff, RGraph.trim(parts[j]));
2461
+ }
2462
+ }
2463
+
2464
+ return grad ? grad : color;
2465
+ };
2466
+
2467
+
2468
+
2469
+
2470
+
2471
+
2472
+
2473
+
2474
+ //
2475
+ // This function handles highlighting an entire data-series for the interactive
2476
+ // key
2477
+ //
2478
+ // @param int index The index of the data series to be highlighted
2479
+ //
2480
+ this.interactiveKeyHighlight = function (index)
2481
+ {
2482
+ if (this.angles && this.angles[index]) {
2483
+
2484
+ var segment = this.angles[index];
2485
+ var x = segment[2];
2486
+ var y = segment[3];
2487
+ var start = segment[0];
2488
+ var end = segment[1];
2489
+
2490
+ this.context.strokeStyle = properties.keyInteractiveHighlightChartStroke;
2491
+ this.context.fillStyle = properties.keyInteractiveHighlightChartFill;
2492
+ this.context.lineWidth = 2;
2493
+ this.context.lineJoin = 'bevel';
2494
+
2495
+ this.context.beginPath();
2496
+ this.context.moveTo(x, y);
2497
+ this.context.arc(x, y, this.radius, start, end, false);
2498
+ this.context.closePath();
2499
+ this.context.fill();
2500
+ this.context.stroke();
2501
+ }
2502
+ };
2503
+
2504
+
2505
+
2506
+
2507
+
2508
+
2509
+
2510
+
2511
+ //
2512
+ // Using a function to add events makes it easier to facilitate method chaining
2513
+ //
2514
+ // @param string type The type of even to add
2515
+ // @param function func
2516
+ //
2517
+ this.on = function (type, func)
2518
+ {
2519
+ if (type.substr(0,2) !== 'on') {
2520
+ type = 'on' + type;
2521
+ }
2522
+
2523
+ if (typeof this[type] !== 'function') {
2524
+ this[type] = func;
2525
+ } else {
2526
+ RGraph.addCustomEventListener(this, type, func);
2527
+ }
2528
+
2529
+ return this;
2530
+ };
2531
+
2532
+
2533
+
2534
+
2535
+
2536
+
2537
+
2538
+
2539
+ //
2540
+ // This function runs once only
2541
+ // (put at the end of the file (before any effects))
2542
+ //
2543
+ this.firstDrawFunc = function ()
2544
+ {
2545
+ };
2546
+
2547
+
2548
+
2549
+
2550
+
2551
+
2552
+
2553
+
2554
+
2555
+ //
2556
+ // Draw a 3D Pie/Donut chart
2557
+ //
2558
+ this.draw3d = function ()
2559
+ {
2560
+ var scaleX = 1.5,
2561
+ depth = properties.variantThreedDepth,
2562
+ prop_shadow = properties.shadow,
2563
+ prop_labels = properties.labels,
2564
+ prop_labelsSticks = properties.labelsSticks,
2565
+ prop_title = properties.title;
2566
+
2567
+ this.set({
2568
+ labels: [],
2569
+ labelsSticks: false,
2570
+ strokestyle: 'rgba(0,0,0,0)',
2571
+ title: ''
2572
+ });
2573
+
2574
+ //
2575
+ // Change the variant so that the draw function doesn't
2576
+ // keep coming in here
2577
+ //
2578
+ this.set({
2579
+ variant: this.get('variant').replace(/3d/, '')
2580
+ });
2581
+
2582
+ this.context.setTransform(scaleX, 0, 0, 1, (this.canvas.width * (scaleX) - this.canvas.width) * -0.5, 0);
2583
+
2584
+ for (var i=depth; i>0; i-=1) {
2585
+
2586
+ this.set({
2587
+ centeryAdjust: i
2588
+ });
2589
+
2590
+ if (i === parseInt(depth / 2) ) {
2591
+ this.set({
2592
+ labels: prop_labels,
2593
+ labelsSticks: prop_labelsSticks
2594
+ });
2595
+ }
2596
+
2597
+ if (i === 0) {
2598
+ this.set({
2599
+ shadow: prop_shadow
2600
+ });
2601
+ }
2602
+
2603
+
2604
+ if (i === 1) {
2605
+ this.set({
2606
+ title: prop_title
2607
+ });
2608
+ }
2609
+
2610
+ this.draw();
2611
+
2612
+ // Turn off the shadow after the bottom pie/donut has
2613
+ // been drawn
2614
+ this.set({
2615
+ shadow: false,
2616
+ title: ''
2617
+ });
2618
+
2619
+ //
2620
+ // If on the middle pie/donut turn the labels and sticks off
2621
+ //
2622
+ if (i <= parseInt(depth / 2) ) {
2623
+ this.set({
2624
+ labels: [],
2625
+ labelsSticks: false
2626
+ });
2627
+ }
2628
+
2629
+ //
2630
+ // Make what we're drawng darker by going over
2631
+ // it in a semi-transparent dark color
2632
+ //
2633
+ if (i > 1) {
2634
+ if (properties.variant.indexOf('donut') !== -1) {
2635
+
2636
+ for (var j=0; j<this.angles.length; ++j) {
2637
+
2638
+ var x = this.angles[j][2];
2639
+ var y = this.angles[j][3];
2640
+ var r1 = this.radius;
2641
+ var r2 = this.radius / 2;
2642
+ var a1 = this.angles[j][0];
2643
+ var a2 = this.angles[j][1];
2644
+
2645
+ this.path(
2646
+ 'b a % % % % % false a % % % % % true f rgba(0,0,0,0.15)',
2647
+ x, y, r1, a1, a2,
2648
+ x, y, r2, a2, a1
2649
+ );
2650
+ }
2651
+
2652
+ // Draw the pie chart darkened segments
2653
+ } else {
2654
+
2655
+ for (var j=0; j<this.angles.length; ++j) {
2656
+
2657
+ var x = this.angles[j][2];
2658
+ var y = this.angles[j][3];
2659
+ var r1 = this.radius;
2660
+ var r2 = this.radius / 2;
2661
+ var a1 = this.angles[j][0];
2662
+ var a2 = this.angles[j][1];
2663
+
2664
+ this.path(
2665
+ 'b m % % a % % % % % false f rgba(0,0,0,0.15)',
2666
+ x, y,
2667
+ x, y, r1 + 1, a1, a2
2668
+ );
2669
+ }
2670
+ }
2671
+ }
2672
+ }
2673
+
2674
+ //
2675
+ // Reset the variant by adding the 3d back on
2676
+ //
2677
+ this.set({
2678
+ variant: this.get('variant') + '3d',
2679
+ shadow: prop_shadow,
2680
+ labels: prop_labels,
2681
+ labelsSticks: prop_labelsSticks,
2682
+ title: prop_title
2683
+ });
2684
+
2685
+ // Necessary to allow method chaining
2686
+ return this;
2687
+ };
2688
+
2689
+
2690
+
2691
+
2692
+
2693
+
2694
+
2695
+
2696
+ //
2697
+ // Pie chart explode
2698
+ //
2699
+ // Explodes the Pie chart - gradually incrementing the size of the explode property
2700
+ //
2701
+ // @param object Options for the effect
2702
+ // @param function An optional callback function to call when the animation completes
2703
+ //
2704
+ this.explode = function ()
2705
+ {
2706
+ // Cancel any stop request if one is pending
2707
+ this.cancelStopAnimation();
2708
+
2709
+ var obj = this;
2710
+ var opt = arguments[0] ? arguments[0] : {};
2711
+ var callback = arguments[1] ? arguments[1] : function () {};
2712
+ var frames = opt.frames ? opt.frames : 30;
2713
+ var frame = 0;
2714
+ var maxExplode = Number(typeof opt.radius === 'number' ? opt.radius : Math.max(this.canvas.width, this.canvas.height));
2715
+ var currentExplode = Number(obj.get('exploded')) || 0;
2716
+
2717
+ if (currentExplode === maxExplode) {
2718
+ currentExplode = 0;
2719
+ this.set('exploded', 0);
2720
+ }
2721
+
2722
+ var step = (maxExplode - currentExplode) / frames;
2723
+
2724
+ // Lose the labels
2725
+ this.set('labels', null);
2726
+
2727
+ // exploded option
2728
+ var iterator = function ()
2729
+ {
2730
+ if (obj.stopAnimationRequested) {
2731
+
2732
+ // Reset the flag
2733
+ obj.stopAnimationRequested = false;
2734
+
2735
+ return;
2736
+ }
2737
+
2738
+ obj.set('exploded', currentExplode + (step * frame) );
2739
+
2740
+ RGraph.clear(obj.canvas);
2741
+ RGraph.redrawCanvas(obj.canvas);
2742
+
2743
+ if (frame++ < frames) {
2744
+ RGraph.Effects.updateCanvas(iterator);
2745
+ } else {
2746
+ callback(obj);
2747
+ }
2748
+ }
2749
+
2750
+ iterator();
2751
+
2752
+ return this;
2753
+ };
2754
+
2755
+
2756
+
2757
+
2758
+
2759
+
2760
+
2761
+
2762
+ //
2763
+ // Pie chart grow
2764
+ //
2765
+ // Gradually increases the pie chart radius
2766
+ //
2767
+ // @param object OPTIONAL An object of options
2768
+ // @param function OPTIONAL A callback function
2769
+ //
2770
+ this.grow = function ()
2771
+ {
2772
+ // Cancel any stop request if one is pending
2773
+ this.cancelStopAnimation();
2774
+
2775
+ var obj = this;
2776
+ var canvas = obj.canvas;
2777
+ var opt = arguments[0] ? arguments[0] : {};
2778
+ var frames = opt.frames || 30;
2779
+ var frame = 0;
2780
+ var callback = arguments[1] ? arguments[1] : function () {};
2781
+ var radius = obj.getRadius();
2782
+
2783
+
2784
+ properties.radius = 0;
2785
+
2786
+ var iterator = function ()
2787
+ {
2788
+ if (obj.stopAnimationRequested) {
2789
+
2790
+ // Reset the flag
2791
+ obj.stopAnimationRequested = false;
2792
+
2793
+ return;
2794
+ }
2795
+
2796
+
2797
+ obj.set('radius', (frame / frames) * radius);
2798
+
2799
+ RGraph.redrawCanvas(canvas);
2800
+
2801
+ if (frame++ < frames) {
2802
+ RGraph.Effects.updateCanvas(iterator);
2803
+
2804
+ } else {
2805
+
2806
+ RGraph.redrawCanvas(obj.canvas);
2807
+
2808
+
2809
+ callback(obj);
2810
+ }
2811
+ };
2812
+
2813
+ iterator();
2814
+
2815
+ return this;
2816
+ };
2817
+
2818
+
2819
+
2820
+
2821
+
2822
+
2823
+
2824
+
2825
+ //
2826
+ // RoundRobin
2827
+ //
2828
+ // This effect does two things:
2829
+ // 1. Gradually increases the size of each segment
2830
+ // 2. Gradually increases the size of the radius from 0
2831
+ //
2832
+ // @param object OPTIONAL Options for the effect
2833
+ // @param function OPTIONAL A callback function
2834
+ //
2835
+ this.roundrobin =
2836
+ this.roundRobin = function ()
2837
+ {
2838
+ // Cancel any stop request if one is pending
2839
+ this.cancelStopAnimation();
2840
+
2841
+ var obj = this,
2842
+ opt = arguments[0] || {},
2843
+ callback = arguments[1] || function () {},
2844
+ frame = 0,
2845
+ frames = opt.frames || 30,
2846
+ radius = obj.getRadius(),
2847
+ labels = obj.get('labels')
2848
+
2849
+ obj.set('events', false);
2850
+ obj.set('labels', []);
2851
+
2852
+ var iterator = function ()
2853
+ {
2854
+ if (obj.stopAnimationRequested) {
2855
+
2856
+ // Reset the flag
2857
+ obj.stopAnimationRequested = false;
2858
+
2859
+ return;
2860
+ }
2861
+
2862
+
2863
+
2864
+ obj.set(
2865
+ 'effectRoundrobinMultiplier',
2866
+ RGraph.Effects.getEasingMultiplier(frames, frame)
2867
+ );
2868
+
2869
+ RGraph.redrawCanvas(obj.canvas);
2870
+
2871
+ if (frame < frames) {
2872
+ RGraph.Effects.updateCanvas(iterator);
2873
+ frame++;
2874
+
2875
+ } else {
2876
+
2877
+ obj.set({
2878
+ events: true,
2879
+ labels: labels
2880
+ });
2881
+
2882
+ RGraph.redrawCanvas(obj.canvas);
2883
+ callback(obj);
2884
+ }
2885
+ };
2886
+
2887
+ iterator();
2888
+
2889
+ return this;
2890
+ };
2891
+
2892
+
2893
+
2894
+
2895
+
2896
+
2897
+
2898
+
2899
+ //
2900
+ // roundRobinSequential
2901
+ //
2902
+ // This function does similar to the above roundRobin
2903
+ // function but increases the segment sizes sequentially
2904
+ // instead of all at once.
2905
+ //
2906
+ // @param object OPTIONAL Options for the effect
2907
+ // @param function OPTIONAL A callback function
2908
+ //
2909
+ this.roundRobinSequential = function ()
2910
+ {
2911
+ var args = RGraph.getArgs(arguments, 'options,callback');
2912
+
2913
+ // Cancel any stop request if one is pending
2914
+ this.cancelStopAnimation();
2915
+
2916
+ var obj = this,
2917
+ opt = args.options || {},
2918
+ callback = args.callback || function () {},
2919
+ frame = 0,
2920
+ frames = opt.frames || 60,
2921
+ radius = this.getRadius(),
2922
+ labels = this.get('labels')
2923
+
2924
+ this.set('events', false);
2925
+ this.set('labels', []);
2926
+
2927
+
2928
+ var radius = Math.max(
2929
+ this.canvas.width,
2930
+ this.canvas.height
2931
+ ) * 2;
2932
+
2933
+ var iterator = function ()
2934
+ {
2935
+ if (obj.stopAnimationRequested) {
2936
+
2937
+ // Reset the flag
2938
+ obj.stopAnimationRequested = false;
2939
+
2940
+ return;
2941
+ }
2942
+
2943
+
2944
+
2945
+
2946
+ // Redraw the Pie/donut chart
2947
+ RGraph.redrawCanvas(obj.canvas);
2948
+
2949
+ // Draw the cover over the canvas
2950
+ obj.path(
2951
+ 'b m % % a % % % % % false f white',
2952
+ obj.centerx,
2953
+ obj.centery,
2954
+ obj.centerx,
2955
+ obj.centery,
2956
+ radius,
2957
+ (0 - RGraph.HALFPI) + ((frame / frames) * RGraph.TWOPI),
2958
+ RGraph.TWOPI - RGraph.HALFPI
2959
+ );
2960
+
2961
+ if (frame < frames) {
2962
+ RGraph.Effects.updateCanvas(iterator);
2963
+ frame++;
2964
+
2965
+ } else {
2966
+
2967
+ obj.set({
2968
+ events: true,
2969
+ labels: labels
2970
+ });
2971
+
2972
+ RGraph.redrawCanvas(obj.canvas);
2973
+ callback(obj);
2974
+ }
2975
+ };
2976
+
2977
+ iterator();
2978
+
2979
+ return this;
2980
+ };
2981
+
2982
+
2983
+
2984
+
2985
+
2986
+
2987
+
2988
+
2989
+ //
2990
+ // Pie chart implode
2991
+ //
2992
+ // Implodes the Pie chart - gradually decreasing the size of the exploded property. It starts at the largest of
2993
+ // the canvas width./height
2994
+ //
2995
+ // @param object Optional options for the effect. You can pass in frames here - such as:
2996
+ // myPie.implode({frames: 60}; function () {alert('Done!');})
2997
+ // @param function A callback function which is called when the effect is finished
2998
+ //
2999
+ this.implode = function ()
3000
+ {
3001
+ // Cancel any stop request if one is pending
3002
+ this.cancelStopAnimation();
3003
+
3004
+ var obj = this,
3005
+ opt = arguments[0] || {},
3006
+ callback = arguments[1] || function (){},
3007
+ frames = opt.frames || 30,
3008
+ frame = 0,
3009
+
3010
+ current_exploded = Number(this.get('exploded'));
3011
+
3012
+ explodedMax = Math.max(this.canvas.width, this.canvas.height),
3013
+ explodedMax = Number(this.get('exploded')) || explodedMax;
3014
+
3015
+ if (Number(this.get('exploded')) === explodedMax) {
3016
+ this.set('exploded', 0);
3017
+ current_exploded = 0;
3018
+ }
3019
+
3020
+
3021
+
3022
+ function iterator ()
3023
+ {
3024
+ if (obj.stopAnimationRequested) {
3025
+
3026
+ // Reset the flag
3027
+ obj.stopAnimationRequested = false;
3028
+
3029
+ return;
3030
+ }
3031
+
3032
+
3033
+
3034
+ exploded = explodedMax - ((frame / frames) * explodedMax);
3035
+
3036
+ // Set the new value
3037
+ obj.set('exploded', exploded);
3038
+
3039
+ RGraph.clear(obj.canvas);
3040
+ RGraph.redrawCanvas(obj.canvas);
3041
+
3042
+ if (frame++ < frames) {
3043
+ RGraph.Effects.updateCanvas(iterator);
3044
+ } else {
3045
+ RGraph.clear(obj.canvas);
3046
+ RGraph.redrawCanvas(obj.canvas);
3047
+ callback(obj);
3048
+ }
3049
+ }
3050
+
3051
+ iterator();
3052
+
3053
+ return this;
3054
+ };
3055
+
3056
+
3057
+
3058
+
3059
+
3060
+
3061
+
3062
+
3063
+ //
3064
+ // Couple of functions that allow you to control the
3065
+ // animation effect
3066
+ //
3067
+ this.stopAnimation = function ()
3068
+ {
3069
+ this.stopAnimationRequested = true;
3070
+ };
3071
+
3072
+ this.cancelStopAnimation = function ()
3073
+ {
3074
+ this.stopAnimationRequested = false;
3075
+ };
3076
+
3077
+
3078
+
3079
+
3080
+
3081
+
3082
+
3083
+
3084
+ //
3085
+ // A worker function that handles Bar chart specific tooltip substitutions
3086
+ //
3087
+ this.tooltipSubstitutions = function (opt)
3088
+ {
3089
+ return {
3090
+ index: opt.index,
3091
+ dataset: 0,
3092
+ sequentialIndex: opt.index,
3093
+ value: this.data[opt.index],
3094
+ values: [this.data[opt.index]]
3095
+ };
3096
+ };
3097
+
3098
+
3099
+
3100
+
3101
+
3102
+
3103
+
3104
+
3105
+ //
3106
+ // A worker function that returns the correct color/label/value
3107
+ //
3108
+ // @param object specific The indexes that are applicable
3109
+ // @param number index The appropriate index
3110
+ //
3111
+ this.tooltipsFormattedCustom = function (specific, index, colors)
3112
+ {
3113
+ var color = colors[specific.index];
3114
+ var label = ( (typeof properties.tooltipsFormattedKeyLabels === 'object' && typeof properties.tooltipsFormattedKeyLabels[specific.index] === 'string') ? properties.tooltipsFormattedKeyLabels[specific.index] : '');
3115
+
3116
+ return {
3117
+ color: color,
3118
+ label: label
3119
+ };
3120
+ };
3121
+
3122
+
3123
+
3124
+
3125
+
3126
+
3127
+
3128
+
3129
+ //
3130
+ // This allows for static tooltip positioning
3131
+ //
3132
+ this.positionTooltipStatic = function (args)
3133
+ {
3134
+ var obj = args.object,
3135
+ e = args.event,
3136
+ tooltip = args.tooltip,
3137
+ index = args.index,
3138
+ canvasXY = RGraph.getCanvasXY(obj.canvas)
3139
+ segment = this.angles[args.index],
3140
+ angle = ((segment[1] - segment[0]) / 2) + segment[0],
3141
+ multiplier = 0.5;
3142
+
3143
+ //
3144
+ // Determine the correct radius to use when calculating the
3145
+ // coordinates of the tooltip
3146
+ //
3147
+ if (properties.variant.indexOf('donut') >= 0) {
3148
+
3149
+ // Determine the radius
3150
+ if (RGraph.isNull(properties.variantDonutWidth)) {
3151
+ var radius = (this.radius / 2) + (this.radius / 4);
3152
+ } else {
3153
+ var radius = (this.radius - properties.variantDonutWidth) + (properties.variantDonutWidth / 2);
3154
+ }
3155
+
3156
+ } else {
3157
+ var radius = this.radius * multiplier;
3158
+ }
3159
+
3160
+ var explosion = typeof properties.exploded == 'number' ? properties.exploded : properties.exploded[index];
3161
+ var endpoint = RGraph.getRadiusEndPoint(
3162
+ this.centerx,
3163
+ this.centery,
3164
+ angle,
3165
+ radius + (explosion || 0)
3166
+ );
3167
+
3168
+ // Allow for the 3D stretching of the canvas
3169
+ if (properties.variant.indexOf('3d') > 0) {
3170
+ var width = properties.variantDonutWidth === 'number' ? properties.variantDonutWidth : this.radius / 2;
3171
+ endpoint[0] = (endpoint[0] - this.centerx) * 1.5 + this.centerx;
3172
+ }
3173
+
3174
+
3175
+ // Position the tooltip in the X direction
3176
+ args.tooltip.style.left = (
3177
+ canvasXY[0] // The X coordinate of the canvas
3178
+ + endpoint[0] // The X coordinate of the shape on the chart
3179
+ - (tooltip.offsetWidth / 2) // Subtract half of the tooltip width
3180
+ + obj.properties.tooltipsOffsetx // Add any user defined offset
3181
+ ) + 'px';
3182
+
3183
+ args.tooltip.style.top = (
3184
+ canvasXY[1] // The Y coordinate of the canvas
3185
+ + endpoint[1] // The Y coordinate of the shape on the chart
3186
+ - tooltip.offsetHeight // The height of the tooltip
3187
+ + obj.properties.tooltipsOffsety // Add any user defined offset
3188
+ - 10 // Account for the pointer
3189
+ ) + 'px';
3190
+ };
3191
+
3192
+
3193
+
3194
+
3195
+
3196
+
3197
+
3198
+
3199
+ //
3200
+ // This returns the relevant value for the formatted key
3201
+ // macro %{value}. THIS VALUE SHOULD NOT BE FORMATTED.
3202
+ //
3203
+ // @param number index The index in the dataset to get
3204
+ // the value for
3205
+ //
3206
+ this.getKeyValue = function (index)
3207
+ {
3208
+ if ( RGraph.isArray(this.properties.keyFormattedValueSpecific)
3209
+ && RGraph.isNumber(this.properties.keyFormattedValueSpecific[index])) {
3210
+
3211
+ return this.properties.keyFormattedValueSpecific[index];
3212
+
3213
+ } else {
3214
+ return this.data[index];
3215
+ }
3216
+ };
3217
+
3218
+
3219
+
3220
+
3221
+
3222
+
3223
+
3224
+
3225
+ //
3226
+ // Returns how many data-points there should be when a string
3227
+ // based key property has been specified. For example, this:
3228
+ //
3229
+ // key: '%{property:_labels[%{index}]} %{value_formatted}'
3230
+ //
3231
+ // ...depending on how many bits of data ther is might get
3232
+ // turned into this:
3233
+ //
3234
+ // key: [
3235
+ // '%{property:_labels[%{index}]} %{value_formatted}',
3236
+ // '%{property:_labels[%{index}]} %{value_formatted}',
3237
+ // '%{property:_labels[%{index}]} %{value_formatted}',
3238
+ // '%{property:_labels[%{index}]} %{value_formatted}',
3239
+ // '%{property:_labels[%{index}]} %{value_formatted}',
3240
+ // ]
3241
+ //
3242
+ // ... ie in that case there would be 4 data-points so the
3243
+ // template is repeated 4 times.
3244
+ //
3245
+ this.getKeyNumDatapoints = function ()
3246
+ {
3247
+ return this.data.length;
3248
+ };
3249
+
3250
+
3251
+
3252
+
3253
+
3254
+
3255
+
3256
+
3257
+ //
3258
+ // Now need to register all chart types. MUST be after the setters/getters are defined
3259
+ //
3260
+ RGraph.register(this);
3261
+
3262
+
3263
+
3264
+
3265
+
3266
+
3267
+
3268
+
3269
+ //
3270
+ // This is the 'end' of the constructor so if the first argument
3271
+ // contains configuration data - handle that.
3272
+ //
3273
+ RGraph.parseObjectStyleConfig(this, conf.options);
3274
+ };