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,84 +1,2420 @@
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.SVG=RGraph.SVG||{};(function(win,doc,undefined)
3
- {var RG=RGraph,ua=navigator.userAgent,ma=Math,win=window,doc=document;RG.SVG.Rose=function(conf)
4
- {this.set=function(name,value)
5
- {if(arguments.length===1&&typeof name==='object'){for(i in arguments[0]){if(typeof i==='string'){name=ret.name;value=ret.value;this.set(name,value);}}}else{var ret=RG.SVG.commonSetter({object:this,name:name,value:value});name=ret.name;value=ret.value;this.properties[name]=value;if(name==='colors'){this.originalColors=RG.SVG.arrayClone(value);this.colorsParsed=false;}}
6
- return this;};this.get=function(name)
7
- {return this.properties[name];};this.id=conf.id;this.uid=RG.SVG.createUID();this.container=document.getElementById(this.id);this.layers={};this.svg=RG.SVG.createSVG({object:this,container:this.container});this.isRGraph=true;this.width=Number(this.svg.getAttribute('width'));this.height=Number(this.svg.getAttribute('height'));this.data=RG.SVG.arrayClone(conf.data);this.originalData=RG.SVG.arrayClone(conf.data);this.type='rose';this.angles=[];this.angles2=[];this.colorsParsed=false;this.originalColors={};this.gradientCounter=1;this.nodes=[];this.shadowNodes=[];this.max=0;this.redraw=false;this.highlight_node=null;this.propertyNameAliases={};RG.SVG.OR.add(this);this.container.style.display='inline-block';this.properties={centerx:null,centery:null,radius:null,marginLeft:35,marginRight:35,marginTop:35,marginBottom:35,amargin:'3deg',backgroundGrid:true,backgroundGridColor:'#ddd',backgroundGridRadialsCount:null,backgroundGridRadialsAngleOffset:0,backgroundGridConcentricsCount:5,backgroundGridLinewidth:1,colorsStroke:'white',colors:['red','black','orange','green','#6ff','#ccc','pink','orange','cyan','maroon','olive','teal'],colorsOpacity:1,textColor:'black',textFont:'Arial, Verdana, sans-serif',textSize:12,textBold:false,textItalic:false,labels:[],labelsFont:null,labelsSize:null,labelsColor:null,labelsBold:null,labelsItalic:null,labelsRadialMargin:10,labelsAngleOffset:0,scaleVisible:true,scaleUnitsPre:'',scaleUnitsPost:'',scaleMax:null,scaleMin:0,scalePoint:'.',scaleThousand:',',scaleRound:false,scaleDecimals:0,scaleFormatter:null,scaleBold:null,scaleItalic:null,scaleColor:null,scaleSize:null,scaleFont:null,scaleLabelsCount:5,linewidth:1,tooltips:null,tooltipsOverride:null,tooltipsEffect:'fade',tooltipsCssClass:'RGraph_tooltip',tooltipsEvent:'click',highlightStroke:'rgba(0,0,0,0)',highlightFill:'rgba(255,255,255,0.7)',highlightLinewidth:1,title:'',titleX:null,titleY:null,titleHalign:'center',titleValign:null,titleSize:null,titleColor:null,titleFont:null,titleBold:null,titleItalic:null,titleSubtitle:null,titleSubtitleX:null,titleSubtitleY:null,titleSubtitleHalign:'center',titleSubtitleValign:null,titleSubtitleSize:null,titleSubtitleColor:'#aaa',titleSubtitleFont:null,titleSubtitleBold:null,titleSubtitleItalic:null,shadow:false,shadowOffsetx:2,shadowOffsety:2,shadowBlur:2,shadowOpacity:0.25,exploded:0,key:null,keyColors:null,keyOffsetx:0,keyOffsety:0,keyLabelsOffsetx:0,keyLabelsOffsety:-1,keyLabelsFont:null,keyLabelsSize:null,keyLabelsColor:null,keyLabelsBold:null,keyLabelsItalic:null,segmentsAngleOffset:0,variant:'normal',effectGrowMultiplier:1,effectRoundrobinMultiplier:1};RG.SVG.getGlobals(this);if(RG.SVG.FX&&typeof RG.SVG.FX.decorate==='function'){RG.SVG.FX.decorate(this);}
8
- var prop=this.properties;this.draw=function()
9
- {RG.SVG.fireCustomEvent(this,'onbeforedraw');this.width=Number(this.svg.getAttribute('width'));this.height=Number(this.svg.getAttribute('height'));this.data=RG.SVG.arrayClone(this.originalData);this.angles=[];for(var i=0;i<this.data.length;++i){this.angles2[i]=[];}
10
- RG.SVG.createDefs(this);this.graphWidth=this.width-prop.marginLeft-prop.marginRight;this.graphHeight=this.height-prop.marginTop-prop.marginBottom;this.centerx=(this.graphWidth/2)+prop.marginLeft;this.centery=(this.graphHeight/2)+prop.marginTop;this.radius=ma.min(this.graphWidth,this.graphHeight)/2;this.centerx=typeof prop.centerx==='number'?prop.centerx:this.centerx;this.centery=typeof prop.centery==='number'?prop.centery:this.centery;this.radius=typeof prop.radius==='number'?prop.radius:this.radius;if(typeof prop.radius==='string'&&prop.radius.match(/^\+|-\d+$/))this.radius+=parseFloat(prop.radius);if(typeof prop.centerx==='string'&&prop.centerx.match(/^\+|-\d+$/))this.centery+=parseFloat(prop.centerx);if(typeof prop.centery==='string'&&prop.centery.match(/^\+|-\d+$/))this.centerx+=parseFloat(prop.centery);if(typeof prop.amargin==='string'&&prop.amargin.match(/([0-9.]+)deg/)){prop.amargin=RegExp.$1/(180/ma.PI);}
11
- for(var i=0;i<this.data.length;++i){if(typeof this.data[i]==='object'){for(var j=0;j<this.data[i].length;++j){if(typeof this.data[i][j]==='string'){this.data[i][j]=RG.SVG.stringsToNumbers(this.data[i][j]);}}}else if(typeof this.data[i]==='string'){this.data[i]=RG.SVG.stringsToNumbers(this.data[i]);}}
12
- this.getMaxValue();RG.SVG.resetColorsToOriginalValues({object:this});this.parseColors();this.scale=RG.SVG.getScale({object:this,numlabels:typeof prop.scaleLabelsCount==='number'?prop.scaleLabelsCount:prop.backgroundGridConcentricCount,unitsPre:prop.scaleUnitsPre,unitsPost:prop.scaleUnitsPost,max:typeof prop.scaleMax==='number'?prop.scaleMax:this.max,min:prop.scaleMin,point:prop.scalePoint,round:prop.scaleRound,thousand:prop.scaleThousand,decimals:prop.scaleDecimals,strict:typeof prop.scaleMax==='number',formatter:prop.scaleFormatter});this.max=this.scale.max;this.drawBackground();this.drawRose();this.drawLabels();RG.SVG.drawTitle(this);if(typeof prop.key!==null&&RG.SVG.drawKey){RG.SVG.drawKey(this);}else if(!RGraph.SVG.isNull(prop.key)){alert('The drawKey() function does not exist - have you forgotten to include the key library?');}
13
- if(prop.shadow){RG.SVG.setShadow({object:this,offsetx:prop.shadowOffsetx,offsety:prop.shadowOffsety,blur:prop.shadowBlur,opacity:prop.shadowOpacity,id:'dropShadow'});}
14
- var obj=this;doc.body.addEventListener('mousedown',function(e)
15
- {obj.hideHighlight(obj);},false);RG.SVG.fireCustomEvent(this,'ondraw');return this;};this.drawBackground=function()
16
- {if(prop.backgroundGrid){var grid=RG.SVG.create({svg:this.svg,parent:this.svg.all,type:'g',attr:{className:'rgraph_radar_grid',fill:'rgba(0,0,0,0)',stroke:prop.backgroundGridColor},style:{pointerEvents:'none'}});var origin=0-(RG.SVG.TRIG.PI/2),radials=(typeof prop.backgroundGridRadialsCount==='number'?prop.backgroundGridRadialsCount:this.data.length),concentrics=prop.backgroundGridConcentricsCount,step=RG.SVG.TRIG.TWOPI/radials;if(radials>0){if(prop.variant==='non-equi-angular'){var radials=this.data.length;for(var i=0,total=0;i<this.data.length;++i){total+=this.data[i][1];}
17
- for(var i=0,sum=0;i<this.data.length;++i){var coords=RG.SVG.TRIG.toCartesian({cx:this.centerx,cy:this.centery,r:this.radius,angle:origin+((sum/total)*RG.SVG.TRIG.TWOPI)+prop.backgroundGridRadialsAngleOffset});var str='M {1} {2} L {3} {4}'.format(this.centerx,this.centery,coords.x,coords.y);RG.SVG.create({svg:this.svg,type:'path',parent:grid,attr:{d:str,stroke:prop.backgroundGridColor,'stroke-width':prop.backgroundGridLinewidth}});sum+=this.data[i][1];}}else{for(var i=0,len=radials;i<len;++i){var coords=RG.SVG.TRIG.toCartesian({cx:this.centerx,cy:this.centery,r:this.radius,angle:origin+(i*step)+prop.backgroundGridRadialsAngleOffset});var str='M {1} {2} L {3} {4}'.format(this.centerx,this.centery,coords.x,coords.y);RG.SVG.create({svg:this.svg,type:'path',parent:grid,attr:{d:str,stroke:prop.backgroundGridColor,'stroke-width':prop.backgroundGridLinewidth}});}}}
18
- if(concentrics>0){for(var j=1;j<=concentrics;j++){RG.SVG.create({svg:this.svg,type:'circle',parent:grid,attr:{cx:this.centerx,cy:this.centery,r:this.radius*(j/concentrics),fill:'transparent',stroke:prop.backgroundGridColor,'stroke-width':prop.backgroundGridLinewidth}});}}}};this.drawRose=function()
19
- {var opt=arguments[0]||{};for(var i=0;i<this.angles.length;++i){this.angles[i].element.parentNode.removeChild(this.angles[i].element);}
20
- this.angles=[];for(var i=0;i<this.data.length;++i){this.angles2[i]=[];}
21
- if(prop.variant==='non-equi-angular'){return this.drawRoseNonEquiAngular(opt);}
22
- var radians=RG.SVG.TRIG.TWOPI/this.data.length;if(!document.getElementById('rgraph_rose_segments_'+this.uid)){var group=RG.SVG.create({svg:this.svg,type:'g',parent:this.svg.all,attr:{id:'rgraph_rose_segments_'+this.uid}});}else{var group=document.getElementById('rgraph_rose_segments_'+this.uid);}
23
- for(var i=0,seq=0;i<this.data.length;++i,++seq){var radius=(this.data[i]/this.scale.max)*this.radius*prop.effectGrowMultiplier,start=(i/this.data.length)*RG.SVG.TRIG.TWOPI*prop.effectRoundrobinMultiplier,end=(((i/this.data.length)*RG.SVG.TRIG.TWOPI)+radians)*prop.effectRoundrobinMultiplier;var explosion=this.getExploded({index:i,start:start-RG.SVG.TRIG.HALFPI,end:end-RG.SVG.TRIG.HALFPI});if(typeof this.data[i]==='object'&&!RG.SVG.isNull(this.data[i])){if(!document.getElementById('rose_'+this.uid+'_segment_group_'+i)){var segment_group=RG.SVG.create({svg:this.svg,type:'g',parent:group,attr:{id:'rose_'+this.uid+'_segment_group_'+i}});}else{var segment_group=document.getElementById('rose_'+this.uid+'_segment_group_'+i)}
24
- for(var j=0,sum=0,accRadius=0;j<this.data[i].length;++j,++seq){if(j===0){prevRadius=0;}
25
- sum+=this.data[i][j];var radius=(sum/this.scale.max)*this.radius*prop.effectGrowMultiplier,cx=this.centerx+(explosion[0]*prop.effectRoundrobinMultiplier),cy=this.centery+(explosion[1]*prop.effectRoundrobinMultiplier);var arcPath=RG.SVG.TRIG.getArcPath2({cx:cx,cy:cy,r:radius,start:((start+prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,end:((end-prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,anticlockwise:false});if(j===0){arcPath='{1} z'.format(arcPath);}else{var arcPath2=RG.SVG.TRIG.getArcPath2({cx:cx,cy:cy,r:prevRadius,start:((end-prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,end:((start+prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,anticlockwise:true});arcPath='{1} L {2} {3} {4}'.format(arcPath,cx,cy,arcPath2);}
26
- var path=RG.SVG.create({svg:this.svg,type:'path',parent:segment_group,attr:{d:arcPath,fill:prop.colorsSequential?prop.colors[seq]:prop.colors[j],'fill-opacity':prop.colorsOpacity,stroke:prop.colorsStroke,'stroke-width':prop.linewidth,'data-tooltip':(!RG.SVG.isNull(prop.tooltips)&&prop.tooltips.length)?prop.tooltips[seq]:'','data-index':i,'data-centerx':cx,'data-centery':cy,'data-group':i,'data-subindex':j,'data-value':this.data[i][j],'data-start-angle':start+prop.amargin+prop.segmentsAngleOffset,'data-end-angle':end-prop.amargin+prop.segmentsAngleOffset,'data-radius':radius,'data-radius-inner':typeof prevRadius==='number'?prevRadius*prop.effectGrowMultiplier:0,'data-sequential-index':seq}});if(prop.tooltips&&prop.tooltips[seq]){if(prop.tooltipsEvent!=='mousemove'){prop.tooltipsEvent='click';}
27
- (function(index,group,seq,obj)
28
- {path.addEventListener(prop.tooltipsEvent,function(e)
29
- {obj.removeHighlight();RG.SVG.tooltip({object:obj,group:group,index:index,sequentialIndex:seq,text:prop.tooltips[seq],event:e});obj.highlight(e.target);var highlight=RG.SVG.REG.get('highlight');if(prop.tooltipsEvent==='mousemove'){highlight.style.cursor='pointer';}},false);if(prop.tooltipsEvent==='click'){path.addEventListener('mousemove',function(e)
30
- {e.target.style.cursor='pointer';},false);}}(j,i,seq,this));}
31
- this.angles.push({object:this,element:path});this.angles2[i].push({object:this,element:path});var prevRadius=radius;}
32
- seq--;}else{var cx=this.centerx+(explosion[0]*prop.effectRoundrobinMultiplier),cy=this.centery+(explosion[1]*prop.effectRoundrobinMultiplier);var arcPath=RG.SVG.TRIG.getArcPath2({cx:cx,cy:cy,r:radius,start:((start+prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,end:((end-prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,anticlockwise:false});var path=RG.SVG.create({svg:this.svg,type:'path',parent:group,attr:{d:'{1} z'.format(arcPath),fill:prop.colorsSequential?prop.colors[i]:prop.colors[0],'fill-opacity':prop.colorsOpacity,stroke:prop.colorsStroke,'stroke-width':prop.linewidth,'data-tooltip':(!RG.SVG.isNull(prop.tooltips)&&prop.tooltips.length)?prop.tooltips[i]:'','data-index':i,'data-centerx':cx,'data-centery':cy,'data-value':this.data[i],'data-start-angle':start+prop.amargin+prop.segmentsAngleOffset,'data-end-angle':end-prop.amargin+prop.segmentsAngleOffset,'data-radius':radius,'data-sequential':seq}});this.angles.push({object:this,element:path});this.angles2[i].push({object:this,element:path});if(prop.tooltips&&prop.tooltips[i]){if(prop.tooltipsEvent!=='mousemove'){prop.tooltipsEvent='click';}
33
- (function(index,obj)
34
- {path.addEventListener(prop.tooltipsEvent,function(e)
35
- {obj.removeHighlight();RG.SVG.tooltip({object:obj,index:index,group:index,sequentialIndex:index,text:prop.tooltips[index],event:e});obj.highlight(e.target);var highlight=RG.SVG.REG.get('highlight');if(prop.tooltipsEvent==='mousemove'){highlight.style.cursor='pointer';}},false);if(prop.tooltipsEvent==='click'){path.addEventListener('mousemove',function(e)
36
- {e.target.style.cursor='pointer';},false);}}(i,this));}}}};this.drawRoseNonEquiAngular=function(opt)
37
- {if(!document.getElementById('rgraph_rose_segments_'+this.uid)){var group=RG.SVG.create({svg:this.svg,type:'g',parent:this.svg.all,attr:{id:'rgraph_rose_segments_'+this.uid}});}else{var group=document.getElementById('rgraph_rose_segments_'+this.uid)}
38
- for(var i=0,total=0;i<this.data.length;++i){total+=parseFloat(this.data[i][1]);}
39
- var start=0;for(var i=0,seq=0;i<this.data.length;++i,++seq){var radians=(this.data[i][1]/total)*RG.SVG.TRIG.TWOPI,end=start+radians;var explosion=this.getExploded({index:i,start:start-RG.SVG.TRIG.HALFPI,end:end-RG.SVG.TRIG.HALFPI});if(typeof this.data[i][0]==='object'&&!RG.SVG.isNull(this.data[i][0])){if(!document.getElementById('rgraph_rose_'+this.uid+'_segment_group_'+i)){var segment_group=RG.SVG.create({svg:this.svg,type:'g',parent:group,attr:{id:'rgraph_rose_'+this.uid+'_segment_group_'+i}});}else{var segment_group=document.getElementById('rgraph_rose_'+this.uid+'_segment_group_'+i)}
40
- for(var j=0,sum=0;j<this.data[i][0].length;++j,++seq){sum+=this.data[i][0][j];if(j===0){var prevRadius=0,radius=(sum/this.scale.max)*this.radius*prop.effectGrowMultiplier,cx=this.centerx+(explosion[0]*prop.effectRoundrobinMultiplier),cy=this.centery+(explosion[1]*prop.effectRoundrobinMultiplier);var arcPath=RG.SVG.TRIG.getArcPath2({cx:cx,cy:cy,r:radius,start:((start+prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,end:((end-prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,anticlockwise:false});var arcPath2='';}else{var prevRadius=radius,radius=(sum/this.scale.max)*this.radius*prop.effectGrowMultiplier,cx=this.centerx+(explosion[0]*prop.effectRoundrobinMultiplier),cy=this.centery+(explosion[1]*prop.effectRoundrobinMultiplier);var arcPath=RG.SVG.TRIG.getArcPath2({cx:cx,cy:cy,r:radius,start:((start+prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,end:((end-prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,anticlockwise:false});var arcPath2=RG.SVG.TRIG.getArcPath2({cx:cx,cy:cy,r:prevRadius,start:((end-prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,end:((start+prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,anticlockwise:true});}
41
- var path=RG.SVG.create({svg:this.svg,type:'path',parent:segment_group,attr:{d:'{1} {2} z'.format(arcPath,arcPath2),fill:prop.colorsSequential?prop.colors[seq]:prop.colors[j],'fill-opacity':prop.colorsOpacity,stroke:prop.colorsStroke,'stroke-width':prop.linewidth,'data-tooltip':(!RG.SVG.isNull(prop.tooltips)&&prop.tooltips.length)?prop.tooltips[i]:'','data-centerx':cx,'data-centery':cy,'data-index':i,'data-subindex':j,'data-value':this.data[i][0][j],'data-start-angle':start+prop.amargin+prop.segmentsAngleOffset,'data-end-angle':end-prop.amargin+prop.segmentsAngleOffset,'data-radius':radius,'data-radius-inner':prevRadius,'data-sequential':seq}});this.angles.push({object:this,element:path});this.angles2[i].push({object:this,element:path});if(prop.tooltips&&prop.tooltips[seq]){if(prop.tooltipsEvent!=='mousemove'){prop.tooltipsEvent='click';}
42
- (function(index,group,seq,obj)
43
- {path.addEventListener(prop.tooltipsEvent,function(e)
44
- {obj.removeHighlight();RG.SVG.tooltip({object:obj,index:index,group:group,sequentialIndex:seq,text:prop.tooltips[seq],event:e});obj.highlight(e.target);var highlight=RG.SVG.REG.get('highlight');if(prop.tooltipsEvent==='mousemove'){highlight.style.cursor='pointer';}},false);if(prop.tooltipsEvent==='click'){path.addEventListener('mousemove',function(e)
45
- {e.target.style.cursor='pointer';},false);}}(j,i,seq,this));}
46
- var prevRadius=radius;}
47
- seq--}else{var radius=(this.data[i][0]/this.scale.max)*this.radius*prop.effectGrowMultiplier,cx=this.centerx+(explosion[0]*prop.effectRoundrobinMultiplier),cy=this.centery+(explosion[1]*prop.effectRoundrobinMultiplier);var arcPath=RG.SVG.TRIG.getArcPath2({cx:cx,cy:cy,r:radius,start:((start+prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,end:((end-prop.amargin)*prop.effectRoundrobinMultiplier)+prop.segmentsAngleOffset,anticlockwise:false});var path=RG.SVG.create({svg:this.svg,type:'path',parent:group,attr:{d:'{1} z'.format(arcPath),fill:prop.colorsSequential?prop.colors[i]:prop.colors[0],'fill-opacity':prop.colorsOpacity,stroke:prop.colorsStroke,'stroke-width':prop.linewidth,'data-tooltip':(!RG.SVG.isNull(prop.tooltips)&&prop.tooltips.length)?prop.tooltips[i]:'','data-centerx':cx,'data-centery':cy,'data-index':i,'data-value':this.data[i][0],'data-start-angle':start+prop.amargin+prop.segmentsAngleOffset,'data-end-angle':end-prop.amargin+prop.segmentsAngleOffset,'data-radius':radius,'data-sequential':seq}});this.angles.push({object:this,element:path});this.angles2[i].push({object:this,element:path});if(prop.tooltips&&prop.tooltips[i]){if(prop.tooltipsEvent!=='mousemove'){prop.tooltipsEvent='click';}
48
- (function(index,group,seq,obj)
49
- {path.addEventListener(prop.tooltipsEvent,function(e)
50
- {obj.removeHighlight();RG.SVG.tooltip({object:obj,index:index,group:index,sequentialIndex:seq,text:prop.tooltips[index],event:e});obj.highlight(e.target);var highlight=RG.SVG.REG.get('highlight');if(prop.tooltipsEvent==='mousemove'){highlight.style.cursor='pointer';}},false);if(prop.tooltipsEvent==='click'){path.addEventListener('mousemove',function(e)
51
- {e.target.style.cursor='pointer';},false);}}(i,i,seq,this));}}
52
- start+=radians;}};this.redrawRose=function()
53
- {};this.drawLabels=function()
54
- {if(prop.scaleVisible){if(!document.getElementById('rgraph_rose_scale_labels_'+this.uid)){var group=RG.SVG.create({svg:this.svg,type:'g',parent:this.svg.all,attr:{id:'rgraph_rose_scale_labels_'+this.uid}});}else{var group=document.getElementById('rgraph_rose_scale_labels_'+this.uid);}
55
- for(var i=0;i<this.scale.labels.length;++i){var x=this.centerx,y=this.centery-(this.radius/this.scale.labels.length*(i+1));RG.SVG.text({object:this,svg:this.svg,parent:group,tag:'labels.scale',text:this.scale.labels[i],x:x,y:y,halign:'center',valign:'center',background:'rgba(255,255,255,0.7)',padding:2,size:typeof prop.scaleSize==='number'?prop.scaleSize:prop.textSize-2,color:prop.scaleColor||prop.textColor,bold:typeof prop.scaleBold==='boolean'?prop.scaleBold:prop.textBold,italic:typeof prop.scaleItalic==='boolean'?prop.scaleItalic:prop.textItalic,font:prop.scaleFont||prop.textFont});}
56
- var str=RG.SVG.numberFormat({object:this,num:this.scale.min.toFixed(prop.scaleDecimals),prepend:prop.scaleUnitsPre,append:prop.scaleUnitsPost,point:prop.scalePoint,thousand:prop.scaleThousand,formatter:prop.scaleFormatter});RG.SVG.text({object:this,svg:this.svg,parent:group,tag:'labels.scale',text:str,x:this.centerx,y:this.centery,halign:'center',valign:'center',background:'rgba(255,255,255,0.7)',padding:2,size:typeof prop.scaleSize==='number'?prop.scaleSize:prop.textSize-2,color:prop.scaleColor||prop.textColor,bold:typeof prop.scaleBold==='boolean'?prop.scaleBold:prop.textBold,italic:typeof prop.scaleItalic==='boolean'?prop.scaleItalic:prop.textItalic,font:prop.scaleFont||prop.textFont});}
57
- var halign;if(!document.getElementById('rgraph_rose_circular_labels_'+this.uid)){var group=RG.SVG.create({svg:this.svg,type:'g',parent:this.svg.all,attr:{id:'rgraph_rose_circular_labels_'+this.uid}});}else{var group=document.getElementById('rgraph_rose_circular_labels_'+this.uid);}
58
- if(typeof prop.labelsSize!=='number'){prop.labelsSize=prop.textSize+4;}
59
- for(var i=0;i<prop.labels.length;++i){if(prop.variant==='non-equi-angular'){var angle=((this.angles2[i][0].end-this.angles2[i][0].start)/2)+this.angles2[i][0].start-RG.SVG.TRIG.HALFPI;}else{var angle=(((RG.SVG.TRIG.TWOPI/prop.labels.length))*i)-RG.SVG.TRIG.HALFPI+prop.labelsAngleOffset+(RG.SVG.TRIG.TWOPI/(2*prop.labels.length));}
60
- var endpoint=RG.SVG.TRIG.getRadiusEndPoint({r:this.radius+prop.labelsRadialMargin,angle:angle});var explosion=this.getExploded({index:i,start:this.angles2[i][0].start-RG.SVG.TRIG.HALFPI,end:this.angles2[i][0].end-RG.SVG.TRIG.HALFPI});endpoint[0]+=this.centerx+explosion[0];endpoint[1]+=this.centery+explosion[1];if(ma.round(endpoint[0])>this.centerx){halign='left';}else if(ma.round(endpoint[0])===this.centerx){halign='center';}else{halign='right';}
61
- RG.SVG.text({object:this,svg:this.svg,parent:group,tag:'labels',text:typeof prop.labels[i]==='string'?prop.labels[i]:'',x:endpoint[0],y:endpoint[1],halign:halign,valign:'center',background:'rgba(255,255,255,0.7)',padding:2,size:typeof prop.labelsSize==='number'?prop.labelsSize:prop.textSize,color:prop.labelsColor||prop.textColor,bold:typeof prop.labelsBold==='boolean'?prop.labelsBold:prop.textBold,italic:typeof prop.labelsItalic==='boolean'?prop.labelsItalic:prop.textItalic,font:prop.labelsFont||prop.textFont});}};this.highlight=function(path)
62
- {var centerx=path.getAttribute('data-centerx'),centery=path.getAttribute('data-centery'),radius=path.getAttribute('data-radius'),radiusInner=path.getAttribute('data-radius-inner'),start=path.getAttribute('data-start-angle'),end=path.getAttribute('data-end-angle');var arcPath=RG.SVG.TRIG.getArcPath3({cx:centerx,cy:centery,r:radius,start:start,end:end,lineto:true});var arcPath_array=RG.SVG.TRIG.getArcPath3({cx:centerx,cy:centery,r:radius,start:start,end:end,lineto:true,array:true});if(radiusInner){var arcPath2=RG.SVG.TRIG.getArcPath3({cx:centerx,cy:centery,r:radiusInner,start:end,end:start,lineto:true,anticlockwise:true});}else{arcPath2=' L {1} {2}'.format(centerx,centery);}
63
- var highlight=RG.SVG.create({svg:this.svg,parent:this.svg.all,type:'path',attr:{d:'M {1} {2} '.format(arcPath_array[1],arcPath_array[2])+arcPath+' '+arcPath2+' z',fill:prop.highlightFill,stroke:prop.highlightStroke,'stroke-width':prop.highlightLinewidth},style:{pointerEvents:'none'}});if(prop.tooltipsEvent==='mousemove'){highlight.addEventListener('mouseout',function(e)
64
- {highlight.parentNode.removeChild(highlight);RG.SVG.hideTooltip();RG.SVG.REG.set('highlight',null);},false);}
65
- RG.SVG.REG.set('highlight',highlight);};this.parseColors=function()
66
- {if(!Object.keys(this.originalColors).length){this.originalColors={colors:RG.SVG.arrayClone(prop.colors),highlightFill:RG.SVG.arrayClone(prop.highlightFill)}}
67
- var colors=prop.colors;if(colors){for(var i=0;i<colors.length;++i){colors[i]=RG.SVG.parseColorRadial({object:this,color:colors[i]});}}
68
- prop.highlightFill=RG.SVG.parseColorRadial({object:this,color:prop.highlightFill});};this.getMaxValue=function()
69
- {var max=0;if(prop.variant==='non-equi-angular'){for(var i=0;i<this.data.length;++i){if(!RG.SVG.isNull(this.data[i])){if(typeof this.data[i][0]==='number'){max=ma.max(max,this.data[i][0]);}else if(typeof this.data[i][0]==='object'){max=ma.max(max,RG.SVG.arraySum(this.data[i][0]));}}}}else{for(var i=0;i<this.data.length;++i){if(!RG.SVG.isNull(this.data[i])){if(typeof this.data[i]==='number'){max=ma.max(max,this.data[i]);}else if(typeof this.data[i]==='object'){max=ma.max(max,RG.SVG.arraySum(this.data[i]));}}}}
70
- this.max=max;};this.getRadius=function(value)
71
- {return((value-prop.scaleMin)/(this.scale.max-prop.scaleMin))*this.radius;};this.roundRobin=function()
72
- {};this.on=function(type,func)
73
- {if(type.substr(0,2)!=='on'){type='on'+type;}
74
- RG.SVG.addCustomEventListener(this,type,func);return this;};this.exec=function(func)
75
- {func(this);return this;};this.removeHighlight=this.hideHighlight=function()
76
- {var highlight=RG.SVG.REG.get('highlight');if(highlight){highlight.setAttribute('fill','transparent');highlight.setAttribute('stroke','transparent');highlight=null;RG.SVG.REG.set('highlight',null);}};this.getExploded=function(opt)
77
- {var index=opt.index,start=opt.start,end=opt.end,exploded=prop.exploded,explodedX,explodedY;if(typeof exploded==='object'&&typeof exploded[index]==='number'){explodedX=ma.cos(((end-start)/2)+start)*exploded[index];explodedY=(ma.sin(((end-start)/2)+start)*exploded[index]);}else if(typeof exploded==='number'){explodedX=ma.cos(((end-start)/2)+start)*exploded;explodedY=ma.sin(((end-start)/2)+start)*exploded;}else{explodedX=0;explodedY=0;}
78
- return[explodedX,explodedY];};this.grow=function(opt)
79
- {var obj=this,opt=arguments[0]||{},frame=-1,frames=opt.frames||60,callback=opt.callback||function(){};prop.effectGrowMultiplier=0.01;this.draw();function iterator()
80
- {++frame;var multiplier=RG.SVG.FX.getEasingMultiplier(frames,frame);prop.effectGrowMultiplier=multiplier;obj.drawRose();if(frame>=frames){callback(obj);}else{RG.SVG.FX.update(iterator);}}
81
- iterator();return this;};this.roundrobin=function(opt)
82
- {var obj=this,opt=arguments[0]||{},frame=-1,frames=opt.frames||60,callback=opt.callback||function(){};prop.effectRoundrobinMultiplier=0.01;this.draw();function iterator()
83
- {++frame;var multiplier=RG.SVG.FX.getEasingMultiplier(frames,frame);prop.effectRoundrobinMultiplier=multiplier;obj.drawRose();if(frame>=frames){callback(obj);}else{RG.SVG.FX.update(iterator);}}
84
- iterator();return this;};for(i in conf.options){if(typeof i==='string'){this.set(i,conf.options[i]);}}};return this;})(window,document);
12
+ RGraph = window.RGraph || {isrgraph:true,isRGraph:true,rgraph:true};
13
+ RGraph.SVG = RGraph.SVG || {};
14
+
15
+ // Module pattern
16
+ (function (win, doc, undefined)
17
+ {
18
+ RGraph.SVG.Rose = function (conf)
19
+ {
20
+ //
21
+ // A setter that the constructor uses (at the end)
22
+ // to set all of the properties
23
+ //
24
+ // @param string name The name of the property to set
25
+ // @param string value The value to set the property to
26
+ //
27
+ this.set = function (name, value)
28
+ {
29
+ if (arguments.length === 1 && typeof name === 'object') {
30
+ for (i in arguments[0]) {
31
+ if (typeof i === 'string') {
32
+
33
+ name = ret.name;
34
+ value = ret.value;
35
+
36
+ this.set(name, value);
37
+ }
38
+ }
39
+
40
+ } else {
41
+
42
+ var ret = RGraph.SVG.commonSetter({
43
+ object: this,
44
+ name: name,
45
+ value: value
46
+ });
47
+
48
+ name = ret.name;
49
+ value = ret.value;
50
+
51
+ this.properties[name] = value;
52
+
53
+ // If setting the colors, update the originalColors
54
+ // property too
55
+ if (name === 'colors') {
56
+ this.originalColors = RGraph.SVG.arrayClone(value);
57
+ this.colorsParsed = false;
58
+ }
59
+ }
60
+
61
+ return this;
62
+ };
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+ //
72
+ // A getter.
73
+ //
74
+ // @param name string The name of the property to get
75
+ //
76
+ this.get = function (name)
77
+ {
78
+ return this.properties[name];
79
+ };
80
+
81
+
82
+
83
+
84
+
85
+
86
+
87
+
88
+ // Convert strings to numbers
89
+ conf.data = RGraph.SVG.stringsToNumbers(conf.data);
90
+ //if (typeof conf.data === 'string') {
91
+ // conf.data = conf.data.split(/,|\|/);
92
+ //}
93
+
94
+ //for (var i=0; i<conf.data.length; ++i) {
95
+ // if (typeof conf.data[i] === 'string') {
96
+ // conf.data[i] = parseFloat(conf.data[i]);
97
+ // }
98
+ //}
99
+
100
+
101
+
102
+
103
+
104
+
105
+ this.id = conf.id;
106
+ this.uid = RGraph.SVG.createUID();
107
+ this.container = document.getElementById(this.id);
108
+ this.layers = {}; // MUST be before the SVG tag is created!
109
+ this.svg = RGraph.SVG.createSVG({object: this,container: this.container});
110
+ this.isRGraph = true;
111
+ this.isrgraph = true;
112
+ this.rgraph = true;
113
+ this.width = Number(this.svg.getAttribute('width'));
114
+ this.height = Number(this.svg.getAttribute('height'));
115
+ this.data = RGraph.SVG.arrayClone(conf.data);
116
+ this.originalData = RGraph.SVG.arrayClone(conf.data);
117
+ this.type = 'rose';
118
+ this.angles = [];
119
+ this.angles2 = [];
120
+ this.colorsParsed = false;
121
+ this.originalColors = {};
122
+ this.gradientCounter = 1;
123
+ this.nodes = [];
124
+ this.shadowNodes = [];
125
+ this.max = 0;
126
+ this.redraw = false;
127
+ this.highlight_node = null;
128
+ this.firstDraw = true; // After the first draw this will be false
129
+
130
+
131
+
132
+
133
+
134
+
135
+ // Add this object to the ObjectRegistry
136
+ RGraph.SVG.OR.add(this);
137
+
138
+ // Set the DIV container to be inline-block
139
+ this.container.style.display = 'inline-block';
140
+
141
+
142
+
143
+
144
+
145
+
146
+
147
+ this.properties =
148
+ {
149
+ centerx: null,
150
+ centery: null,
151
+ radius: null,
152
+
153
+ marginLeft: 35,
154
+ marginRight: 35,
155
+ marginTop: 35,
156
+ marginBottom: 35,
157
+ amargin: '3deg',
158
+
159
+ backgroundGrid: true,
160
+ backgroundGridColor: '#ddd',
161
+ backgroundGridRadialsCount: null,
162
+ backgroundGridRadialsAngleOffset: 0,
163
+ backgroundGridConcentricsCount: 5,
164
+ backgroundGridLinewidth: 1,
165
+
166
+ colorsStroke: 'white',
167
+ colors: [
168
+ 'red', 'black', 'orange', 'green', '#6ff', '#ccc',
169
+ 'pink', 'orange', 'cyan', 'maroon', 'olive', 'teal'
170
+ ],
171
+ colorsOpacity: 1,
172
+
173
+ textColor: 'black',
174
+ textFont: 'Arial, Verdana, sans-serif',
175
+ textSize: 12,
176
+ textBold: false,
177
+ textItalic: false,
178
+ text: null,
179
+
180
+ labels: [],
181
+ labelsFont: null,
182
+ labelsSize: null,
183
+ labelsColor: null,
184
+ labelsBold: null,
185
+ labelsItalic: null,
186
+ labelsRadialMargin: 10,
187
+ labelsAngleOffset: 0,
188
+ labelsFormattedDecimals: 0,
189
+ labelsFormattedPoint: '.',
190
+ labelsFormattedThousand: ',',
191
+ labelsFormattedUnitsPre: '',
192
+ labelsFormattedUnitsPost: '',
193
+
194
+ scaleVisible: true,
195
+ scaleUnitsPre: '',
196
+ scaleUnitsPost: '',
197
+ scaleMax: null,
198
+ scaleMin: 0,
199
+ scalePoint: '.',
200
+ scaleThousand: ',',
201
+ scaleRound: false,
202
+ scaleDecimals: 0,
203
+ scaleFormatter: null,
204
+ scaleBold: null,
205
+ scaleItalic: null,
206
+ scaleColor: null,
207
+ scaleSize: null,
208
+ scaleFont: null,
209
+ scaleLabelsCount: 5,
210
+
211
+ linewidth: 1,
212
+
213
+ tooltips: null,
214
+ tooltipsOverride: null,
215
+ tooltipsEffect: 'fade',
216
+ tooltipsCssClass: 'RGraph_tooltip',
217
+ tooltipsCss: null,
218
+ tooltipsEvent: 'click',
219
+ tooltipsFormattedThousand: ',',
220
+ tooltipsFormattedPoint: '.',
221
+ tooltipsFormattedDecimals: 0,
222
+ tooltipsFormattedUnitsPre: '',
223
+ tooltipsFormattedUnitsPost: '',
224
+ tooltipsFormattedKeyColors: null,
225
+ tooltipsFormattedKeyColorsShape: 'square',
226
+ tooltipsFormattedKeyLabels: [],
227
+ tooltipsFormattedTableHeaders: null,
228
+ tooltipsFormattedTableData: null,
229
+ tooltipsPointer: true,
230
+ tooltipsPointerOffsetx: 0,
231
+ tooltipsPointerOffsety: 0,
232
+ tooltipsPositionStatic: true,
233
+
234
+ highlightStroke: 'rgba(0,0,0,0)',
235
+ highlightFill: 'rgba(255,255,255,0.7)',
236
+ highlightLinewidth: 1,
237
+
238
+ title: '',
239
+ titleX: null,
240
+ titleY: null,
241
+ titleHalign: 'center',
242
+ titleValign: null,
243
+ titleSize: null,
244
+ titleColor: null,
245
+ titleFont: null,
246
+ titleBold: null,
247
+ titleItalic: null,
248
+
249
+ titleSubtitle: null,
250
+ titleSubtitleSize: null,
251
+ titleSubtitleColor: '#aaa',
252
+ titleSubtitleFont: null,
253
+ titleSubtitleBold: null,
254
+ titleSubtitleItalic: null,
255
+
256
+ shadow: false,
257
+ shadowOffsetx: 2,
258
+ shadowOffsety: 2,
259
+ shadowBlur: 2,
260
+ shadowColor: 'rgba(0,0,0,0.25)',
261
+
262
+ exploded: 0,
263
+
264
+
265
+ key: null,
266
+ keyColors: null,
267
+ keyOffsetx: 0,
268
+ keyOffsety: 0,
269
+ keyLabelsOffsetx: 0,
270
+ keyLabelsOffsety: -1,
271
+ keyLabelsFont: null,
272
+ keyLabelsSize: null,
273
+ keyLabelsColor: null,
274
+ keyLabelsBold: null,
275
+ keyLabelsItalic: null,
276
+
277
+ segmentsAngleOffset: 0,
278
+ variant: 'normal',
279
+
280
+ effectGrowMultiplier: 1,// Do not delete this
281
+ effectRoundrobinMultiplier: 1 // Do not delete this
282
+ };
283
+
284
+
285
+
286
+
287
+ //
288
+ // Copy the global object properties to this instance
289
+ //
290
+ RGraph.SVG.getGlobals(this);
291
+
292
+
293
+
294
+
295
+
296
+
297
+ //
298
+ // "Decorate" the object with the generic effects if the effects library has been included
299
+ //
300
+ if (RGraph.SVG.FX && typeof RGraph.SVG.FX.decorate === 'function') {
301
+ RGraph.SVG.FX.decorate(this);
302
+ }
303
+
304
+
305
+
306
+
307
+
308
+ // Add the responsive function to the object
309
+ this.responsive = RGraph.SVG.responsive;
310
+
311
+
312
+
313
+
314
+
315
+ var properties = this.properties;
316
+
317
+
318
+
319
+
320
+
321
+
322
+
323
+
324
+ //
325
+ // The draw method draws the Bar chart
326
+ //
327
+ this.draw = function ()
328
+ {
329
+ // Fire the beforedraw event
330
+ RGraph.SVG.fireCustomEvent(this, 'onbeforedraw');
331
+
332
+
333
+
334
+ // Should the first thing that's done inthe.draw() function
335
+ // except for the onbeforedraw event
336
+ this.width = Number(this.svg.getAttribute('width'));
337
+ this.height = Number(this.svg.getAttribute('height'));
338
+
339
+
340
+
341
+ // Change this to maintain BC
342
+ if (typeof properties.marginInner !== 'undefined') {
343
+ properties.amargin = properties.marginInner;
344
+ }
345
+
346
+
347
+
348
+ // Reset the data back to the original values
349
+ this.data = RGraph.SVG.arrayClone(this.originalData);
350
+
351
+
352
+
353
+ // Reset the angles array to stop it growing
354
+ this.angles = [];
355
+
356
+ // Create the arrays in the angles2 array based on
357
+ // the data that we've been passed
358
+ for (var i=0; i<this.data.length; ++i) {
359
+ this.angles2[i] = [];
360
+ }
361
+
362
+
363
+
364
+
365
+
366
+ // Create the defs tag if necessary
367
+ RGraph.SVG.createDefs(this);
368
+
369
+
370
+
371
+
372
+ this.graphWidth = this.width - properties.marginLeft - properties.marginRight;
373
+ this.graphHeight = this.height - properties.marginTop - properties.marginBottom;
374
+
375
+
376
+
377
+ // Work out the center point
378
+ this.centerx = (this.graphWidth / 2) + properties.marginLeft;
379
+ this.centery = (this.graphHeight / 2) + properties.marginTop;
380
+ this.radius = Math.min(this.graphWidth, this.graphHeight) / 2;
381
+
382
+
383
+
384
+ // Allow the user to override the calculated centerx/y/radius
385
+ this.centerx = typeof properties.centerx === 'number' ? properties.centerx : this.centerx;
386
+ this.centery = typeof properties.centery === 'number' ? properties.centery : this.centery;
387
+ this.radius = typeof properties.radius === 'number' ? properties.radius : this.radius;
388
+
389
+ //
390
+ // Allow the centerx/centery/radius to be a plus/minus
391
+ //
392
+ if (typeof properties.radius === 'string' && properties.radius.match(/^\+|-\d+$/) ) this.radius += parseFloat(properties.radius);
393
+ if (typeof properties.centerx === 'string' && properties.centerx.match(/^\+|-\d+$/) ) this.centery += parseFloat(properties.centerx);
394
+ if (typeof properties.centery === 'string' && properties.centery.match(/^\+|-\d+$/) ) this.centerx += parseFloat(properties.centery);
395
+
396
+
397
+
398
+
399
+
400
+ //
401
+ // Convert the nargin from strings to a number
402
+ //
403
+ if (typeof properties.amargin === 'string' && properties.amargin.match(/([0-9.]+)deg/)) {
404
+ properties.amargin = RegExp.$1 / (180 / Math.PI);
405
+ }
406
+
407
+
408
+
409
+
410
+ //
411
+ // Add the data to the .originalData array and work out the max value
412
+ //
413
+ // 2/5/14 Now also use this loop to ensure that the data pieces
414
+ // are numbers
415
+ //
416
+ // **Is this necessary **
417
+ //
418
+ //if (RGraph.SVG.isArray(this.data) && (typeof this.data[0] === 'number' || typeof this.data[0] === 'string')) {
419
+ // this.data = [this.data];
420
+ //}
421
+
422
+ // Convert strings to numbers
423
+ for (var i=0; i<this.data.length; ++i) {
424
+ if (typeof this.data[i] === 'object') {
425
+ for (var j=0; j<this.data[i].length; ++j) {
426
+ if (typeof this.data[i][j] === 'string') {
427
+ this.data[i][j] = RGraph.SVG.stringsToNumbers(this.data[i][j]);
428
+ }
429
+ }
430
+ } else if (typeof this.data[i] === 'string') {
431
+ this.data[i] = RGraph.SVG.stringsToNumbers(this.data[i]);
432
+ }
433
+ }
434
+
435
+
436
+
437
+
438
+
439
+
440
+
441
+
442
+
443
+ // Get the max value. This sets the maximum value on the
444
+ // this.max variable
445
+ this.getMaxValue();
446
+
447
+
448
+
449
+
450
+
451
+
452
+
453
+ // Parse the colors for gradients
454
+ RGraph.SVG.resetColorsToOriginalValues({object:this});
455
+ this.parseColors();
456
+
457
+ //
458
+ // Get the scale
459
+ //
460
+
461
+ this.scale = RGraph.SVG.getScale({
462
+ object: this,
463
+ numlabels: typeof properties.scaleLabelsCount === 'number' ? properties.scaleLabelsCount : properties.backgroundGridConcentricCount,
464
+ unitsPre: properties.scaleUnitsPre,
465
+ unitsPost: properties.scaleUnitsPost,
466
+ max: typeof properties.scaleMax === 'number' ? properties.scaleMax : this.max,
467
+ min: properties.scaleMin,
468
+ point: properties.scalePoint,
469
+ round: properties.scaleRound,
470
+ thousand: properties.scaleThousand,
471
+ decimals: properties.scaleDecimals,
472
+ strict: typeof properties.scaleMax === 'number',
473
+ formatter: properties.scaleFormatter
474
+ });
475
+
476
+ this.max = this.scale.max;
477
+
478
+
479
+
480
+ // Draw the background 'grid'
481
+ this.drawBackground();
482
+
483
+
484
+
485
+ // Draw the chart
486
+ this.drawRose();
487
+
488
+
489
+
490
+
491
+
492
+
493
+ // Draw the labels
494
+ this.drawLabels();
495
+
496
+
497
+
498
+ // Draw the title and subtitle
499
+ RGraph.SVG.drawTitle(this);
500
+
501
+
502
+
503
+
504
+
505
+
506
+ // Draw the key
507
+ if (typeof properties.key !== null && RGraph.SVG.drawKey) {
508
+ RGraph.SVG.drawKey(this);
509
+ } else if (!RGraph.SVG.isNull(properties.key)) {
510
+ alert('The drawKey() function does not exist - have you forgotten to include the key library?');
511
+ }
512
+
513
+ // Create the shadow definition if needed
514
+ if (properties.shadow) {
515
+ RGraph.SVG.setShadow({
516
+ object: this,
517
+ offsetx: properties.shadowOffsetx,
518
+ offsety: properties.shadowOffsety,
519
+ blur: properties.shadowBlur,
520
+ color: properties.shadowColor,
521
+ id: 'dropShadow'
522
+ });
523
+ }
524
+
525
+
526
+
527
+ // Add the event listener that clears the highlight if
528
+ // there is any. Must be MOUSEDOWN (ie before the click event)
529
+ var obj = this;
530
+ document.body.addEventListener('mousedown', function (e)
531
+ {
532
+ obj.hideHighlight(obj);
533
+ }, false);
534
+
535
+
536
+
537
+
538
+
539
+
540
+
541
+
542
+ //
543
+ // Allow the addition of custom text via the
544
+ // text: property.
545
+ //
546
+ RGraph.SVG.addCustomText(this);
547
+
548
+
549
+
550
+
551
+
552
+
553
+
554
+
555
+
556
+
557
+
558
+
559
+ //
560
+ // Fire the onfirstdraw event
561
+ //
562
+ if (this.firstDraw) {
563
+ this.firstDraw = false;
564
+ RGraph.SVG.fireCustomEvent(this, 'onfirstdraw');
565
+ }
566
+
567
+
568
+
569
+
570
+ // Fire the draw event
571
+ RGraph.SVG.fireCustomEvent(this, 'ondraw');
572
+
573
+
574
+
575
+
576
+
577
+
578
+
579
+ //
580
+ // Install any inline responsive configuration. This
581
+ // should be last in the draw function - even after
582
+ // the draw events.
583
+ //
584
+ RGraph.SVG.installInlineResponsive(this);
585
+
586
+
587
+
588
+
589
+
590
+
591
+
592
+
593
+
594
+
595
+
596
+ return this;
597
+ };
598
+
599
+
600
+
601
+
602
+
603
+
604
+
605
+
606
+ //
607
+ // New create() shortcut function
608
+ // For example:
609
+ // this.create('rect,x:0,y:0,width:100,height:100'[,parent]);
610
+ //
611
+ // @param str string The tag definition to parse and create
612
+ // @param object The (optional) parent element
613
+ // @return object The new tag
614
+ //
615
+ this.create = function (str)
616
+ {
617
+ var def = RGraph.SVG.create.parseStr(this, str);
618
+ def.svg = this.svg;
619
+
620
+ // By default the parent is the SVG tag - but if
621
+ // requested then change it to the tag that has
622
+ // been given
623
+ if (arguments[1]) {
624
+ def.parent = arguments[1];
625
+ }
626
+
627
+ return RGraph.SVG.create(def);
628
+ };
629
+
630
+
631
+
632
+
633
+
634
+
635
+
636
+
637
+ //
638
+ // Draw the background grid
639
+ //
640
+ this.drawBackground = function ()
641
+ {
642
+ if (properties.backgroundGrid) {
643
+
644
+ // Create the background grid group tag
645
+ var grid = RGraph.SVG.create({
646
+ svg: this.svg,
647
+ parent: this.svg.all,
648
+ type: 'g',
649
+ attr: {
650
+ className: 'rgraph_radar_grid',
651
+ fill: 'rgba(0,0,0,0)',
652
+ stroke: properties.backgroundGridColor
653
+ },
654
+ style: {
655
+ pointerEvents: 'none'
656
+ }
657
+ });
658
+
659
+ // Draw the concentric "rings" grid lines that are
660
+ // arranged around the centerx/centery along with
661
+ // the radials that eminate from the center outwards
662
+
663
+ var origin = 0 - (RGraph.SVG.TRIG.PI / 2),
664
+ radials = (typeof properties.backgroundGridRadialsCount === 'number' ? properties.backgroundGridRadialsCount : this.data.length),
665
+ concentrics = properties.backgroundGridConcentricsCount,
666
+ step = RGraph.SVG.TRIG.TWOPI / radials;
667
+
668
+
669
+
670
+
671
+
672
+ // First draw the radial lines that emanate from the
673
+ // center outwards
674
+ if (radials > 0) {
675
+ // This draws the radials for the non-equi-angular ONLY
676
+ if (properties.variant === 'non-equi-angular') {
677
+
678
+
679
+
680
+
681
+
682
+
683
+
684
+
685
+
686
+
687
+
688
+
689
+
690
+
691
+ // Number of radials always matches the number of data pieces
692
+ var radials = this.data.length;
693
+
694
+ // Work out the total of the second part of each data bit
695
+ for (var i=0,total=0; i<this.data.length; ++i) {
696
+ total += this.data[i][1];
697
+ }
698
+
699
+ for (var i=0,sum=0; i<this.data.length; ++i) {
700
+
701
+ var coords = RGraph.SVG.TRIG.toCartesian({
702
+ cx: this.centerx,
703
+ cy: this.centery,
704
+ r: this.radius,
705
+ angle: origin + ( (sum / total) * RGraph.SVG.TRIG.TWOPI) + properties.backgroundGridRadialsAngleOffset
706
+ });
707
+
708
+ var str = 'M {1} {2} L {3} {4}'.format(
709
+ this.centerx,
710
+ this.centery,
711
+ coords.x,
712
+ coords.y
713
+ );
714
+
715
+ RGraph.SVG.create({
716
+ svg: this.svg,
717
+ type: 'path',
718
+ parent: grid,
719
+ attr: {
720
+ d: str,
721
+ stroke: properties.backgroundGridColor,
722
+ 'stroke-width': properties.backgroundGridLinewidth
723
+ }
724
+ });
725
+
726
+ sum += this.data[i][1];
727
+ }
728
+
729
+
730
+
731
+
732
+
733
+
734
+
735
+
736
+
737
+
738
+
739
+
740
+ // This draws the radials for normal and STACKED Rose charts
741
+ } else {
742
+ for (var i=0,len=radials; i<len; ++i) {
743
+
744
+ var coords = RGraph.SVG.TRIG.toCartesian({
745
+ cx: this.centerx,
746
+ cy: this.centery,
747
+ r: this.radius,
748
+ angle: origin + (i * step) + properties.backgroundGridRadialsAngleOffset
749
+ });
750
+
751
+ var str = 'M {1} {2} L {3} {4}'.format(
752
+ this.centerx,
753
+ this.centery,
754
+ coords.x,
755
+ coords.y
756
+ );
757
+
758
+ RGraph.SVG.create({
759
+ svg: this.svg,
760
+ type: 'path',
761
+ parent: grid,
762
+ attr: {
763
+ d: str,
764
+ stroke: properties.backgroundGridColor,
765
+ 'stroke-width': properties.backgroundGridLinewidth
766
+ }
767
+ });
768
+ }
769
+ }
770
+ }
771
+
772
+
773
+
774
+
775
+
776
+ // Draw the concentrics
777
+ if (concentrics > 0) {
778
+
779
+ for (var j=1; j<=concentrics; j++) {
780
+
781
+ // Add circle to the scene
782
+ RGraph.SVG.create({
783
+ svg: this.svg,
784
+ type: 'circle',
785
+ parent: grid,
786
+ attr: {
787
+ cx: this.centerx,
788
+ cy: this.centery,
789
+ r: this.radius * (j/concentrics),
790
+ fill: 'transparent',
791
+ stroke: properties.backgroundGridColor,
792
+ 'stroke-width': properties.backgroundGridLinewidth
793
+ }
794
+ });
795
+ }
796
+ }
797
+ }
798
+ };
799
+
800
+
801
+
802
+
803
+
804
+
805
+
806
+
807
+ //
808
+ // Draws the Rose chart
809
+ //
810
+ this.drawRose = function ()
811
+ {
812
+ var opt = arguments[0] || {};
813
+
814
+
815
+ // Empty the this.coords array so that animations don't
816
+ // continually add new segments on top of old ones.
817
+ for (var i=0; i<this.angles.length; ++i) {
818
+ this.angles[i].element.parentNode.removeChild(this.angles[i].element);
819
+ }
820
+
821
+
822
+
823
+
824
+
825
+
826
+ // Reset the angles array to stop it growing.
827
+ //
828
+ // This needs to be here so that the grow effect does cause the
829
+ // angles arrays to grow and grow and grow...
830
+ this.angles = [];
831
+
832
+ // Create the arrays in the angles2 array based on
833
+ // the data that we've been passed
834
+ for (var i=0; i<this.data.length; ++i) {
835
+ this.angles2[i] = [];
836
+ }
837
+
838
+
839
+
840
+
841
+ // Jump to another function if we're drawing a non-equi-angular chart
842
+ if (properties.variant === 'non-equi-angular') {
843
+ return this.drawRoseNonEquiAngular(opt);
844
+ }
845
+
846
+
847
+
848
+
849
+
850
+
851
+ var radians = RGraph.SVG.TRIG.TWOPI / this.data.length;
852
+
853
+ // Don't add this group twice
854
+ if (!document.getElementById('rgraph_rose_segments_' + this.uid)) {
855
+ var group = RGraph.SVG.create({
856
+ svg: this.svg,
857
+ type:'g',
858
+ parent: this.svg.all,
859
+ attr: {
860
+ id: 'rgraph_rose_segments_' + this.uid
861
+ }
862
+ });
863
+ } else {
864
+ var group = document.getElementById('rgraph_rose_segments_' + this.uid);
865
+ }
866
+
867
+
868
+ // Now loop thru the data
869
+ for (var i=0,seq=0; i<this.data.length; ++i,++seq) {
870
+
871
+ var radius = (this.data[i] / this.scale.max) * this.radius * properties.effectGrowMultiplier,
872
+ start = (i / this.data.length) * RGraph.SVG.TRIG.TWOPI * properties.effectRoundrobinMultiplier,
873
+ end = (((i / this.data.length) * RGraph.SVG.TRIG.TWOPI) + radians) * properties.effectRoundrobinMultiplier;
874
+
875
+ // Get the exploded distance
876
+ var explosion = this.getExploded({
877
+ index: i,
878
+ start: start - RGraph.SVG.TRIG.HALFPI,
879
+ end: end - RGraph.SVG.TRIG.HALFPI
880
+ });
881
+
882
+
883
+
884
+
885
+
886
+
887
+
888
+
889
+
890
+
891
+
892
+
893
+
894
+
895
+
896
+
897
+
898
+
899
+
900
+ // Is the data piece an array or a number?
901
+ if (typeof this.data[i] === 'object' && !RGraph.SVG.isNull(this.data[i])) {
902
+
903
+ // Create a group for the parts of this segment
904
+ if (!document.getElementById('rose_' + this.uid + '_segment_group_' + i)) {
905
+ var segment_group = RGraph.SVG.create({
906
+ svg: this.svg,
907
+ type: 'g',
908
+ parent: group,
909
+ attr: {
910
+ id: 'rose_' + this.uid + '_segment_group_' + i
911
+ }
912
+ });
913
+ } else {
914
+ var segment_group = document.getElementById('rose_' + this.uid + '_segment_group_' + i)
915
+ }
916
+
917
+ for (var j=0,sum=0,accRadius=0; j<this.data[i].length; ++j,++seq) {
918
+
919
+ //
920
+ // Must reset the prevradius variable
921
+ //
922
+ if (j === 0) {
923
+ prevRadius = 0;
924
+ }
925
+
926
+ sum += this.data[i][j];
927
+
928
+ var radius = (sum / this.scale.max) * this.radius * properties.effectGrowMultiplier,
929
+ cx = this.centerx + (explosion[0] * properties.effectRoundrobinMultiplier),
930
+ cy = this.centery + (explosion[1] * properties.effectRoundrobinMultiplier);
931
+
932
+ // This (I think is the OUTER curve in the segment
933
+ var arcPath = RGraph.SVG.TRIG.getArcPath2({
934
+ cx: cx,
935
+ cy: cy,
936
+ r: radius,
937
+ start: ((start + properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
938
+ end: ((end - properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
939
+ anticlockwise: false
940
+ });
941
+
942
+ // The inner most segment
943
+ if (j === 0) {
944
+ arcPath = '{1} z'.format(
945
+ arcPath
946
+ );
947
+ } else {
948
+
949
+ var arcPath2 = RGraph.SVG.TRIG.getArcPath2({
950
+ cx: cx,
951
+ cy: cy,
952
+ r: prevRadius,
953
+ start: ((end - properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
954
+ end: ((start + properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
955
+ anticlockwise: true
956
+ });
957
+ arcPath = '{1} L {2} {3} {4}'.format(
958
+ arcPath,
959
+ cx,
960
+ cy,
961
+ arcPath2
962
+ );
963
+ }
964
+
965
+ var path = RGraph.SVG.create({
966
+ svg: this.svg,
967
+ type: 'path',
968
+ parent: segment_group,
969
+ attr: {
970
+ d: arcPath,
971
+ fill: properties.colorsSequential ? properties.colors[seq] : properties.colors[j],
972
+ 'fill-opacity': properties.colorsOpacity,
973
+ stroke: properties.colorsStroke,
974
+ 'stroke-width': properties.linewidth,
975
+
976
+ 'data-tooltip': (!RGraph.SVG.isNull(properties.tooltips) && properties.tooltips.length) ? properties.tooltips[seq] : '',
977
+ 'data-index': i,
978
+ 'data-centerx': cx,
979
+ 'data-centery': cy,
980
+ 'data-group': i,
981
+ 'data-subindex': j,
982
+ 'data-value': this.data[i][j],
983
+ 'data-start-angle': start + properties.amargin + properties.segmentsAngleOffset,
984
+ 'data-end-angle': end - properties.amargin + properties.segmentsAngleOffset,
985
+ 'data-radius': radius,
986
+ 'data-radius-inner': typeof prevRadius === 'number' ? prevRadius * properties.effectGrowMultiplier : 0,
987
+ 'data-sequential-index': seq
988
+ }
989
+ });
990
+
991
+
992
+ // Install the tooltip listener
993
+ if (properties.tooltips && (properties.tooltips[seq] || typeof properties.tooltips === 'string') ) {
994
+
995
+ // Make the tooltipsEvent default to click
996
+ if (properties.tooltipsEvent !== 'mousemove') {
997
+ properties.tooltipsEvent = 'click';
998
+ }
999
+
1000
+ (function (index, group, seq, obj)
1001
+ {
1002
+ path.addEventListener(properties.tooltipsEvent, function (e)
1003
+ {
1004
+ obj.removeHighlight();
1005
+
1006
+ // Show the tooltip
1007
+ RGraph.SVG.tooltip({
1008
+ object: obj,
1009
+ group: group,
1010
+ index: index,
1011
+ sequentialIndex: seq,
1012
+ text: typeof properties.tooltips === 'string' ? properties.tooltips : properties.tooltips[seq],
1013
+ event: e
1014
+ });
1015
+
1016
+ // Highlight the segment that has been clicked on
1017
+ obj.highlight(e.target);
1018
+
1019
+ var highlight = RGraph.SVG.REG.get('highlight');
1020
+
1021
+ if (properties.tooltipsEvent === 'mousemove') {
1022
+ highlight.style.cursor = 'pointer';
1023
+ }
1024
+
1025
+ }, false);
1026
+
1027
+ // Install the event listener that changes the
1028
+ // cursor if necessary
1029
+ if (properties.tooltipsEvent === 'click') {
1030
+ path.addEventListener('mousemove', function (e)
1031
+ {
1032
+ e.target.style.cursor = 'pointer';
1033
+ }, false);
1034
+ }
1035
+
1036
+ }(j, i, seq, this));
1037
+ }
1038
+
1039
+ // Add the segment to the angles and angles2 array
1040
+ this.angles.push({
1041
+ object: this,
1042
+ element: path
1043
+ });
1044
+
1045
+ this.angles2[i].push({
1046
+ object: this,
1047
+ element: path
1048
+ });
1049
+
1050
+ var prevRadius = radius;
1051
+ }
1052
+
1053
+
1054
+
1055
+
1056
+
1057
+
1058
+
1059
+
1060
+
1061
+
1062
+ seq--;
1063
+
1064
+
1065
+
1066
+
1067
+
1068
+
1069
+
1070
+
1071
+
1072
+
1073
+
1074
+
1075
+
1076
+ // A regular number
1077
+ } else {
1078
+
1079
+ var cx = this.centerx + (explosion[0] * properties.effectRoundrobinMultiplier),
1080
+ cy = this.centery + (explosion[1] * properties.effectRoundrobinMultiplier);
1081
+
1082
+ var arcPath = RGraph.SVG.TRIG.getArcPath2({
1083
+ cx: cx,
1084
+ cy: cy,
1085
+ r: radius,
1086
+ start: ((start + properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
1087
+ end: ((end - properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
1088
+ anticlockwise: false
1089
+ });
1090
+
1091
+ var path = RGraph.SVG.create({
1092
+ svg: this.svg,
1093
+ type: 'path',
1094
+ parent: group,
1095
+ attr: {
1096
+ d: '{1} z'.format(
1097
+ arcPath
1098
+ ),
1099
+ fill: properties.colorsSequential ? properties.colors[i] : properties.colors[0],
1100
+ 'fill-opacity': properties.colorsOpacity,
1101
+ stroke: properties.colorsStroke,
1102
+ 'stroke-width': properties.linewidth,
1103
+
1104
+ 'data-tooltip': (!RGraph.SVG.isNull(properties.tooltips) && properties.tooltips.length) ? properties.tooltips[i] : '',
1105
+ 'data-index': i,
1106
+ 'data-centerx': cx,
1107
+ 'data-centery': cy,
1108
+ 'data-value': this.data[i],
1109
+ 'data-start-angle': start + properties.amargin + properties.segmentsAngleOffset,
1110
+ 'data-end-angle': end - properties.amargin + properties.segmentsAngleOffset,
1111
+ 'data-radius': radius,
1112
+ 'data-sequential': seq
1113
+ }
1114
+ });
1115
+
1116
+ // Add the segment to the angles array
1117
+ this.angles.push({
1118
+ object: this,
1119
+ element: path
1120
+ });
1121
+
1122
+ this.angles2[i].push({
1123
+ object: this,
1124
+ element: path
1125
+ });
1126
+
1127
+
1128
+
1129
+
1130
+ if (properties.tooltips && (properties.tooltips[i] || typeof properties.tooltips === 'string') ) {
1131
+
1132
+ // Make the tooltipsEvent default to click
1133
+ if (properties.tooltipsEvent !== 'mousemove') {
1134
+ properties.tooltipsEvent = 'click';
1135
+ }
1136
+
1137
+ (function (index, obj)
1138
+ {
1139
+ path.addEventListener(properties.tooltipsEvent, function (e)
1140
+ {
1141
+ obj.removeHighlight();
1142
+
1143
+ // Show the tooltip
1144
+ RGraph.SVG.tooltip({
1145
+ object: obj,
1146
+ index: index,
1147
+ group: index,
1148
+ sequentialIndex: index,
1149
+ text: typeof properties.tooltips === 'string' ? properties.tooltips : properties.tooltips[index],
1150
+ event: e
1151
+ });
1152
+
1153
+ // Highlight the rect that has been clicked on
1154
+ obj.highlight(e.target);
1155
+
1156
+ var highlight = RGraph.SVG.REG.get('highlight');
1157
+
1158
+ if (properties.tooltipsEvent === 'mousemove') {
1159
+ highlight.style.cursor = 'pointer';
1160
+ }
1161
+
1162
+ }, false);
1163
+
1164
+ // Install the event listener that changes the
1165
+ // cursor if necessary
1166
+ if (properties.tooltipsEvent === 'click') {
1167
+ path.addEventListener('mousemove', function (e)
1168
+ {
1169
+ e.target.style.cursor = 'pointer';
1170
+ }, false);
1171
+ }
1172
+
1173
+ }(i, this));
1174
+ }
1175
+ }
1176
+ }
1177
+ };
1178
+
1179
+
1180
+
1181
+
1182
+
1183
+
1184
+
1185
+
1186
+ //
1187
+ // Draws the radar, but only the non-equi-angular variant
1188
+ //
1189
+ this.drawRoseNonEquiAngular = function (opt)
1190
+ {
1191
+ if (!document.getElementById('rgraph_rose_segments_' + this.uid)) {
1192
+ var group = RGraph.SVG.create({
1193
+ svg: this.svg,
1194
+ type:'g',
1195
+ parent: this.svg.all,
1196
+ attr: {
1197
+ id: 'rgraph_rose_segments_' + this.uid
1198
+ }
1199
+ });
1200
+ } else {
1201
+ var group = document.getElementById('rgraph_rose_segments_' + this.uid)
1202
+ }
1203
+
1204
+ //Loop through the data summing the second data-pieces
1205
+ for (var i=0,total=0; i<this.data.length; ++i) {
1206
+ total += parseFloat(this.data[i][1]);
1207
+ }
1208
+
1209
+
1210
+
1211
+
1212
+
1213
+
1214
+
1215
+
1216
+
1217
+
1218
+
1219
+ // The initial angles
1220
+ var start = 0;
1221
+
1222
+
1223
+
1224
+
1225
+ // Now loop thru the data
1226
+ for (var i=0,seq=0; i<this.data.length; ++i,++seq) {
1227
+
1228
+ var radians = (this.data[i][1] / total) * RGraph.SVG.TRIG.TWOPI,
1229
+ end = start + radians;
1230
+
1231
+ // Get the exploded distance
1232
+ var explosion = this.getExploded({
1233
+ index: i,
1234
+ start: start - RGraph.SVG.TRIG.HALFPI,
1235
+ end: end - RGraph.SVG.TRIG.HALFPI
1236
+ });
1237
+
1238
+
1239
+
1240
+
1241
+
1242
+
1243
+
1244
+
1245
+
1246
+
1247
+
1248
+
1249
+
1250
+
1251
+
1252
+ // A stacked non-equi-angular segment
1253
+ if (typeof this.data[i][0] === 'object' && !RGraph.SVG.isNull(this.data[i][0])) {
1254
+
1255
+ if (!document.getElementById('rgraph_rose_' + this.uid + '_segment_group_' + i)) {
1256
+ var segment_group = RGraph.SVG.create({
1257
+ svg: this.svg,
1258
+ type:'g',
1259
+ parent: group,
1260
+ attr: {
1261
+ id: 'rgraph_rose_' + this.uid + '_segment_group_' + i
1262
+ }
1263
+ });
1264
+ } else {
1265
+ var segment_group = document.getElementById('rgraph_rose_' + this.uid + '_segment_group_' + i)
1266
+ }
1267
+
1268
+ // Loop thru the set of values for this segment
1269
+ for (var j=0,sum=0; j<this.data[i][0].length; ++j,++seq) {
1270
+
1271
+ sum += this.data[i][0][j];
1272
+
1273
+ // First segment in the stack or not?
1274
+ if (j === 0) {
1275
+
1276
+ var prevRadius = 0,
1277
+ radius = (sum / this.scale.max) * this.radius * properties.effectGrowMultiplier,
1278
+ cx = this.centerx + (explosion[0] * properties.effectRoundrobinMultiplier),
1279
+ cy = this.centery + (explosion[1] * properties.effectRoundrobinMultiplier);
1280
+
1281
+ var arcPath = RGraph.SVG.TRIG.getArcPath2({
1282
+ cx: cx,
1283
+ cy: cy,
1284
+ r: radius,
1285
+ start: ((start + properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
1286
+ end: ((end - properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
1287
+ anticlockwise: false
1288
+ });
1289
+
1290
+ var arcPath2 = '';
1291
+
1292
+ } else {
1293
+
1294
+ var prevRadius = radius, // The previous iterations radius
1295
+ radius = (sum / this.scale.max) * this.radius * properties.effectGrowMultiplier,
1296
+ cx = this.centerx + (explosion[0] * properties.effectRoundrobinMultiplier),
1297
+ cy = this.centery + (explosion[1] * properties.effectRoundrobinMultiplier);
1298
+
1299
+ var arcPath = RGraph.SVG.TRIG.getArcPath2({
1300
+ cx: cx,
1301
+ cy: cy,
1302
+ r: radius,
1303
+ start: ((start + properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
1304
+ end: ((end - properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
1305
+ anticlockwise: false
1306
+ });
1307
+
1308
+ var arcPath2 = RGraph.SVG.TRIG.getArcPath2({
1309
+ cx: cx,
1310
+ cy: cy,
1311
+ r: prevRadius,
1312
+ start: ((end - properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
1313
+ end: ((start + properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
1314
+ anticlockwise: true
1315
+ });
1316
+ }
1317
+
1318
+ var path = RGraph.SVG.create({
1319
+ svg: this.svg,
1320
+ type: 'path',
1321
+ parent: segment_group,
1322
+ attr: {
1323
+ d: '{1} {2} z'.format(
1324
+ arcPath,
1325
+ arcPath2
1326
+ ),
1327
+ fill: properties.colorsSequential ? properties.colors[seq] : properties.colors[j],
1328
+ 'fill-opacity': properties.colorsOpacity,
1329
+ stroke: properties.colorsStroke,
1330
+ 'stroke-width': properties.linewidth,
1331
+ 'data-tooltip': (!RGraph.SVG.isNull(properties.tooltips) && properties.tooltips.length) ? properties.tooltips[i] : '',
1332
+ 'data-centerx': cx,
1333
+ 'data-centery': cy,
1334
+ 'data-index': i,
1335
+ 'data-subindex': j,
1336
+ 'data-value': this.data[i][0][j],
1337
+ 'data-start-angle': start + properties.amargin + properties.segmentsAngleOffset,
1338
+ 'data-end-angle': end - properties.amargin + properties.segmentsAngleOffset,
1339
+ 'data-radius': radius,
1340
+ 'data-radius-inner': prevRadius,
1341
+ 'data-sequential': seq
1342
+ }
1343
+ });
1344
+
1345
+
1346
+
1347
+ // Add the segment to the angles array
1348
+ this.angles.push({
1349
+ object: this,
1350
+ element: path
1351
+ });
1352
+
1353
+ this.angles2[i].push({
1354
+ object: this,
1355
+ element: path
1356
+ });
1357
+
1358
+
1359
+
1360
+
1361
+ // Install tooltips listeners
1362
+ if (properties.tooltips && (properties.tooltips[seq] || typeof properties.tooltips === 'string') ) {
1363
+
1364
+ // Make the tooltipsEvent default to click
1365
+ if (properties.tooltipsEvent !== 'mousemove') {
1366
+ properties.tooltipsEvent = 'click';
1367
+ }
1368
+
1369
+ (function (index,group,seq,obj)
1370
+ {
1371
+ path.addEventListener(properties.tooltipsEvent, function (e)
1372
+ {
1373
+ obj.removeHighlight();
1374
+
1375
+ // Show the tooltip
1376
+ RGraph.SVG.tooltip({
1377
+ object: obj,
1378
+ index: index,
1379
+ group: group,
1380
+ sequentialIndex: seq,
1381
+ text: typeof properties.tooltips === 'string' ? properties.tooltips : properties.tooltips[seq],
1382
+ event: e
1383
+ });
1384
+
1385
+ // Highlight the rect that has been clicked on
1386
+ obj.highlight(e.target);
1387
+
1388
+ var highlight = RGraph.SVG.REG.get('highlight');
1389
+
1390
+ if (properties.tooltipsEvent === 'mousemove') {
1391
+ highlight.style.cursor = 'pointer';
1392
+ }
1393
+
1394
+ }, false);
1395
+
1396
+ // Install the event listener that changes the
1397
+ // cursor if necessary
1398
+ if (properties.tooltipsEvent === 'click') {
1399
+ path.addEventListener('mousemove', function (e)
1400
+ {
1401
+ e.target.style.cursor = 'pointer';
1402
+ }, false);
1403
+ }
1404
+
1405
+ }(j, i, seq, this));
1406
+ }
1407
+ var prevRadius = radius;
1408
+ }
1409
+ seq--
1410
+
1411
+
1412
+
1413
+
1414
+
1415
+
1416
+
1417
+
1418
+
1419
+
1420
+
1421
+
1422
+
1423
+
1424
+
1425
+
1426
+
1427
+
1428
+
1429
+
1430
+ // A regular non-equi-angular segment
1431
+ } else {
1432
+ var radius = (this.data[i][0] / this.scale.max) * this.radius * properties.effectGrowMultiplier,
1433
+ cx = this.centerx + (explosion[0] * properties.effectRoundrobinMultiplier),
1434
+ cy = this.centery + (explosion[1] * properties.effectRoundrobinMultiplier);
1435
+
1436
+ var arcPath = RGraph.SVG.TRIG.getArcPath2({
1437
+ cx: cx,
1438
+ cy: cy,
1439
+ r: radius,
1440
+ start: ((start + properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
1441
+ end: ((end - properties.amargin) * properties.effectRoundrobinMultiplier) + properties.segmentsAngleOffset,
1442
+ anticlockwise: false
1443
+ });
1444
+
1445
+ var path = RGraph.SVG.create({
1446
+ svg: this.svg,
1447
+ type: 'path',
1448
+ parent: group,
1449
+ attr: {
1450
+ d: '{1} z'.format(
1451
+ arcPath
1452
+ ),
1453
+ fill: properties.colorsSequential ? properties.colors[i] : properties.colors[0],
1454
+ 'fill-opacity': properties.colorsOpacity,
1455
+ stroke: properties.colorsStroke,
1456
+ 'stroke-width': properties.linewidth,
1457
+
1458
+ 'data-tooltip': (!RGraph.SVG.isNull(properties.tooltips) && properties.tooltips.length) ? properties.tooltips[i] : '',
1459
+ 'data-centerx': cx,
1460
+ 'data-centery': cy,
1461
+ 'data-index': i,
1462
+ 'data-value': this.data[i][0],
1463
+ 'data-start-angle': start + properties.amargin + properties.segmentsAngleOffset,
1464
+ 'data-end-angle': end - properties.amargin + properties.segmentsAngleOffset,
1465
+ 'data-radius': radius,
1466
+ 'data-sequential': seq
1467
+ }
1468
+ });
1469
+
1470
+ // Add the segment to the angles array
1471
+ this.angles.push({
1472
+ object: this,
1473
+ element: path
1474
+ });
1475
+
1476
+ this.angles2[i].push({
1477
+ object: this,
1478
+ element: path
1479
+ });
1480
+
1481
+
1482
+
1483
+
1484
+ if (properties.tooltips && (properties.tooltips[i] || typeof properties.tooltips === 'string') ) {
1485
+
1486
+ // Make the tooltipsEvent default to click
1487
+ if (properties.tooltipsEvent !== 'mousemove') {
1488
+ properties.tooltipsEvent = 'click';
1489
+ }
1490
+
1491
+ (function (index, group, seq, obj)
1492
+ {
1493
+ path.addEventListener(properties.tooltipsEvent, function (e)
1494
+ {
1495
+ obj.removeHighlight();
1496
+
1497
+ // Show the tooltip
1498
+ RGraph.SVG.tooltip({
1499
+ object: obj,
1500
+ index: index,
1501
+ group: index,
1502
+ sequentialIndex: seq,
1503
+ text: typeof properties.tooltips === 'string' ? properties.tooltips : properties.tooltips[index],
1504
+ event: e
1505
+ });
1506
+
1507
+ // Highlight the rect that has been clicked on
1508
+ obj.highlight(e.target);
1509
+
1510
+ var highlight = RGraph.SVG.REG.get('highlight');
1511
+
1512
+ if (properties.tooltipsEvent === 'mousemove') {
1513
+ highlight.style.cursor = 'pointer';
1514
+ }
1515
+
1516
+ }, false);
1517
+
1518
+ // Install the event listener that changes the
1519
+ // cursor if necessary
1520
+ if (properties.tooltipsEvent === 'click') {
1521
+ path.addEventListener('mousemove', function (e)
1522
+ {
1523
+ e.target.style.cursor = 'pointer';
1524
+ }, false);
1525
+ }
1526
+
1527
+ }(i, i, seq, this));
1528
+ }
1529
+ }
1530
+
1531
+
1532
+ // Increment the start angle for the next iteration of the loop
1533
+ start += radians;
1534
+ }
1535
+ };
1536
+
1537
+
1538
+
1539
+
1540
+
1541
+
1542
+
1543
+
1544
+ //
1545
+ // Redraws the chart if required
1546
+ //
1547
+ this.redrawRose = function ()
1548
+ {
1549
+ };
1550
+
1551
+
1552
+
1553
+
1554
+
1555
+
1556
+
1557
+
1558
+ //
1559
+ // Draw the labels
1560
+ //
1561
+ this.drawLabels = function ()
1562
+ {
1563
+ //
1564
+ // If the labels option is a string then turn it
1565
+ // into an array.
1566
+ //
1567
+ if (properties.labels && properties.labels.length) {
1568
+
1569
+ if (typeof properties.labels === 'string') {
1570
+ properties.labels = RGraph.SVG.arrayPad({
1571
+ array: [],
1572
+ length: this.data.length,
1573
+ value: properties.labels
1574
+ });
1575
+ }
1576
+
1577
+ // Label substitution
1578
+ //
1579
+ for (var i=0; i<properties.labels.length; ++i) {
1580
+ properties.labels[i] = RGraph.SVG.labelSubstitution({
1581
+ object: this,
1582
+ text: properties.labels[i],
1583
+ index: i,
1584
+ value: this.data[i],
1585
+ decimals: properties.labelsFormattedDecimals || 0,
1586
+ unitsPre: properties.labelsFormattedUnitsPre || '',
1587
+ unitsPost: properties.labelsFormattedUnitsPost || '',
1588
+ thousand: properties.labelsFormattedThousand || ',',
1589
+ point: properties.labelsFormattedPoint || '.'
1590
+ });
1591
+ }
1592
+ }
1593
+
1594
+
1595
+
1596
+
1597
+
1598
+ // Draw the scale if required
1599
+ if (properties.scaleVisible) {
1600
+
1601
+
1602
+
1603
+
1604
+ // Don't add this group twice
1605
+ if (!document.getElementById('rgraph_rose_scale_labels_' + this.uid)) {
1606
+ var group = RGraph.SVG.create({
1607
+ svg: this.svg,
1608
+ type:'g',
1609
+ parent: this.svg.all,
1610
+ attr: {
1611
+ id: 'rgraph_rose_scale_labels_' + this.uid
1612
+ }
1613
+ });
1614
+ } else {
1615
+ var group = document.getElementById('rgraph_rose_scale_labels_' + this.uid);
1616
+ }
1617
+
1618
+ // Get the text configuration
1619
+ var textConf = RGraph.SVG.getTextConf({
1620
+ object: this,
1621
+ prefix: 'scale'
1622
+ });
1623
+
1624
+
1625
+
1626
+ for (var i=0; i<this.scale.labels.length; ++i) {
1627
+
1628
+ var x = this.centerx,
1629
+ y = this.centery - (this.radius / this.scale.labels.length * (i+1) );
1630
+
1631
+
1632
+
1633
+ RGraph.SVG.text({
1634
+
1635
+ object: this,
1636
+ svg: this.svg,
1637
+ parent: group,
1638
+
1639
+ tag: 'labels.scale',
1640
+
1641
+ text: this.scale.labels[i],
1642
+
1643
+ x: x,
1644
+ y: y,
1645
+
1646
+ halign: 'center',
1647
+ valign: 'center',
1648
+
1649
+ background: 'rgba(255,255,255,0.7)',
1650
+ padding: 2,
1651
+
1652
+ size: textConf.size,
1653
+ color: textConf.color,
1654
+ bold: textConf.bold,
1655
+ italic: textConf.italic,
1656
+ font: textConf.font
1657
+ });
1658
+ }
1659
+
1660
+ // Draw the zero label
1661
+ var str = RGraph.SVG.numberFormat({
1662
+ object: this,
1663
+ num: this.scale.min.toFixed(properties.scaleDecimals),
1664
+ prepend: properties.scaleUnitsPre,
1665
+ append: properties.scaleUnitsPost,
1666
+ point: properties.scalePoint,
1667
+ thousand: properties.scaleThousand,
1668
+ formatter: properties.scaleFormatter
1669
+ });
1670
+
1671
+
1672
+ RGraph.SVG.text({
1673
+
1674
+ object: this,
1675
+ parent: group,
1676
+ tag: 'labels.scale',
1677
+
1678
+ text: str,
1679
+
1680
+ x: this.centerx,
1681
+ y: this.centery,
1682
+
1683
+ halign: 'center',
1684
+ valign: 'center',
1685
+
1686
+ background: 'rgba(255,255,255,0.7)',
1687
+ padding: 2,
1688
+
1689
+ size: textConf.size,
1690
+ color: textConf.color,
1691
+ bold: textConf.bold,
1692
+ italic: textConf.italic,
1693
+ font: textConf.font
1694
+ });
1695
+ }
1696
+
1697
+
1698
+
1699
+
1700
+
1701
+
1702
+
1703
+ // Used further down
1704
+ var halign;
1705
+
1706
+
1707
+ // Don't add this group twice
1708
+ if (!document.getElementById('rgraph_rose_circular_labels_' + this.uid)) {
1709
+ var group = RGraph.SVG.create({
1710
+ svg: this.svg,
1711
+ type:'g',
1712
+ parent: this.svg.all,
1713
+ attr: {
1714
+ id: 'rgraph_rose_circular_labels_' + this.uid
1715
+ }
1716
+ });
1717
+ } else {
1718
+ var group = document.getElementById('rgraph_rose_circular_labels_' + this.uid);
1719
+ }
1720
+
1721
+ // Set a default size for the labels
1722
+ if (typeof properties.labelsSize !== 'number') {
1723
+ properties.labelsSize = properties.textSize + 4;
1724
+ }
1725
+
1726
+
1727
+
1728
+ // Draw the circular labels
1729
+
1730
+ // Get the text configuration for the circular labels
1731
+ var textConf = RGraph.SVG.getTextConf({
1732
+ object: this,
1733
+ prefix: 'labels'
1734
+ });
1735
+
1736
+ for (var i=0; i<properties.labels.length; ++i) {
1737
+
1738
+ if (properties.variant === 'non-equi-angular') {
1739
+ var angle = ((Number(this.angles2[i][0].element.getAttribute('data-end-angle')) - Number(this.angles2[i][0].element.getAttribute('data-start-angle'))) / 2) + Number(this.angles2[i][0].element.getAttribute('data-start-angle')) - RGraph.SVG.TRIG.HALFPI;
1740
+ } else {
1741
+ var angle = (((RGraph.SVG.TRIG.TWOPI / properties.labels.length)) * i) - RGraph.SVG.TRIG.HALFPI + properties.labelsAngleOffset + (RGraph.SVG.TRIG.TWOPI / (2 * properties.labels.length));
1742
+ }
1743
+
1744
+ var endpoint = RGraph.SVG.TRIG.getRadiusEndPoint({
1745
+ r: this.radius + properties.labelsRadialMargin,
1746
+ angle: angle
1747
+ });
1748
+
1749
+ // Accommodate the explosion for the label
1750
+ var explosion = this.getExploded({
1751
+ index: i,
1752
+ start: Number(this.angles2[i][0].element.getAttribute('data-start-angle')) - RGraph.SVG.TRIG.HALFPI,
1753
+ end: Number(this.angles2[i][0].element.getAttribute('data-end-angle')) - RGraph.SVG.TRIG.HALFPI
1754
+ });
1755
+
1756
+
1757
+ endpoint[0] += this.centerx + explosion[0];
1758
+ endpoint[1] += this.centery + explosion[1];
1759
+
1760
+
1761
+ // Do the alignment based on which quadrant the label is in
1762
+ if (Math.round(endpoint[0]) > this.centerx) {
1763
+ halign = 'left';
1764
+ } else if (Math.round(endpoint[0]) === this.centerx) {
1765
+ halign = 'center';
1766
+ } else {
1767
+ halign = 'right';
1768
+ }
1769
+
1770
+
1771
+
1772
+
1773
+
1774
+ RGraph.SVG.text({
1775
+
1776
+ object: this,
1777
+ svg: this.svg,
1778
+ parent: group,
1779
+ tag: 'labels',
1780
+
1781
+ text: typeof properties.labels[i] === 'string' ? properties.labels[i] : '',
1782
+
1783
+ x: endpoint[0],
1784
+ y: endpoint[1],
1785
+
1786
+ halign: halign,
1787
+ valign: 'center',
1788
+
1789
+ background: 'rgba(255,255,255,0.7)',
1790
+ padding:2,
1791
+
1792
+ size: textConf.size,
1793
+ color: textConf.color,
1794
+ bold: textConf.bold,
1795
+ italic: textConf.italic,
1796
+ font: textConf.font
1797
+ });
1798
+ }
1799
+ };
1800
+
1801
+
1802
+
1803
+
1804
+
1805
+
1806
+
1807
+
1808
+ //
1809
+ // This function can be used to highlight a segment on the chart
1810
+ //
1811
+ // @param object circle The circle to highlight
1812
+ //
1813
+ this.highlight = function (path)
1814
+ {
1815
+ //
1816
+ // Get the details of the segment and then uswe the arcPath as
1817
+ // the d attribute to a path object.
1818
+ //
1819
+ var centerx = path.getAttribute('data-centerx'),
1820
+ centery = path.getAttribute('data-centery'),
1821
+ radius = path.getAttribute('data-radius'),
1822
+ radiusInner = path.getAttribute('data-radius-inner'),
1823
+ start = path.getAttribute('data-start-angle'),
1824
+ end = path.getAttribute('data-end-angle');
1825
+
1826
+ var arcPath = RGraph.SVG.TRIG.getArcPath3({
1827
+ cx: centerx,
1828
+ cy: centery,
1829
+ r: radius,
1830
+ start: start,
1831
+ end: end,
1832
+ lineto: true
1833
+ });
1834
+
1835
+ var arcPath_array = RGraph.SVG.TRIG.getArcPath3({
1836
+ cx: centerx,
1837
+ cy: centery,
1838
+ r: radius,
1839
+ start: start,
1840
+ end: end,
1841
+ lineto: true,
1842
+ array: true
1843
+ });
1844
+
1845
+ if (radiusInner) {
1846
+ var arcPath2 = RGraph.SVG.TRIG.getArcPath3({
1847
+ cx: centerx,
1848
+ cy: centery,
1849
+ r: radiusInner,
1850
+ start: end,
1851
+ end: start,
1852
+ lineto: true,
1853
+ anticlockwise: true
1854
+ });
1855
+ } else {
1856
+ arcPath2 = ' L {1} {2}'.format(centerx, centery);
1857
+ }
1858
+
1859
+ var highlight = RGraph.SVG.create({
1860
+ svg: this.svg,
1861
+ parent: this.svg.all,
1862
+ type: 'path',
1863
+ attr: {
1864
+ d: 'M {1} {2} '.format(arcPath_array[1], arcPath_array[2]) + arcPath + ' ' + arcPath2 + ' z',
1865
+ fill: properties.highlightFill,
1866
+ stroke: properties.highlightStroke,
1867
+ 'stroke-width': properties.highlightLinewidth
1868
+ },
1869
+ style: {
1870
+ pointerEvents: 'none'
1871
+ }
1872
+ });
1873
+
1874
+
1875
+ if (properties.tooltipsEvent === 'mousemove') {
1876
+ highlight.addEventListener('mouseout', function (e)
1877
+ {
1878
+ highlight.parentNode.removeChild(highlight);
1879
+ RGraph.SVG.hideTooltip();
1880
+
1881
+ RGraph.SVG.REG.set('highlight', null);
1882
+ }, false);
1883
+ }
1884
+
1885
+
1886
+ // Store the highlight rect in the registry so
1887
+ // it can be cleared later
1888
+ RGraph.SVG.REG.set('highlight', highlight);
1889
+ };
1890
+
1891
+
1892
+
1893
+
1894
+
1895
+
1896
+
1897
+
1898
+ //
1899
+ // This allows for easy specification of gradients
1900
+ //
1901
+ this.parseColors = function ()
1902
+ {
1903
+ // Save the original colors so that they can be restored when the canvas is reset
1904
+ if (!Object.keys(this.originalColors).length) {
1905
+ this.originalColors = {
1906
+ colors: RGraph.SVG.arrayClone(properties.colors),
1907
+ highlightFill: RGraph.SVG.arrayClone(properties.highlightFill)
1908
+ }
1909
+ }
1910
+
1911
+
1912
+ // colors
1913
+ var colors = properties.colors;
1914
+
1915
+ if (colors) {
1916
+ for (var i=0; i<colors.length; ++i) {
1917
+ colors[i] = RGraph.SVG.parseColorRadial({
1918
+ object: this,
1919
+ color: colors[i]
1920
+ });
1921
+ }
1922
+ }
1923
+
1924
+ // Highlight fill
1925
+ properties.highlightFill = RGraph.SVG.parseColorRadial({
1926
+ object: this,
1927
+ color: properties.highlightFill
1928
+ });
1929
+ };
1930
+
1931
+
1932
+
1933
+
1934
+
1935
+
1936
+
1937
+
1938
+ //
1939
+ // Get the maximum value
1940
+ //
1941
+ this.getMaxValue = function ()
1942
+ {
1943
+ var max = 0;
1944
+
1945
+ if (properties.variant === 'non-equi-angular') {
1946
+ for (var i=0; i<this.data.length; ++i) {
1947
+ if (!RGraph.SVG.isNull(this.data[i])) {
1948
+ if (typeof this.data[i][0] === 'number') {
1949
+ max = Math.max(max, this.data[i][0]);
1950
+ } else if (typeof this.data[i][0] === 'object'){
1951
+ max = Math.max(max, RGraph.SVG.arraySum(this.data[i][0]));
1952
+ }
1953
+ }
1954
+ }
1955
+ } else {
1956
+ for (var i=0; i<this.data.length; ++i) {
1957
+ if (!RGraph.SVG.isNull(this.data[i])) {
1958
+ if (typeof this.data[i] === 'number') {
1959
+ max = Math.max(max, this.data[i]);
1960
+ } else if (typeof this.data[i] === 'object') {
1961
+ max = Math.max(max, RGraph.SVG.arraySum(this.data[i]));
1962
+ }
1963
+ }
1964
+ }
1965
+ }
1966
+
1967
+ this.max = max;
1968
+ };
1969
+
1970
+
1971
+
1972
+
1973
+
1974
+
1975
+
1976
+
1977
+ //
1978
+ // Gets the radius of a value
1979
+ //
1980
+ //@param number The value to get the radius for
1981
+ //
1982
+ this.getRadius = function (value)
1983
+ {
1984
+ return ( (value - properties.scaleMin) / (this.scale.max - properties.scaleMin) ) * this.radius;
1985
+ };
1986
+
1987
+
1988
+
1989
+
1990
+
1991
+
1992
+
1993
+
1994
+ //
1995
+ // A roundRobin effect for the Pie chart
1996
+ //
1997
+ // @param object Options for the effect
1998
+ // @param function An optional callback function to call when
1999
+ // the effect is complete
2000
+ //
2001
+ this.roundRobin = function ()
2002
+ {
2003
+ };
2004
+
2005
+
2006
+
2007
+
2008
+
2009
+
2010
+
2011
+
2012
+ //
2013
+ // Using a function to add events makes it easier to facilitate method
2014
+ // chaining
2015
+ //
2016
+ // @param string type The type of even to add
2017
+ // @param function func
2018
+ //
2019
+ this.on = function (type, func)
2020
+ {
2021
+ if (type.substr(0,2) !== 'on') {
2022
+ type = 'on' + type;
2023
+ }
2024
+
2025
+ RGraph.SVG.addCustomEventListener(this, type, func);
2026
+
2027
+ return this;
2028
+ };
2029
+
2030
+
2031
+
2032
+
2033
+
2034
+
2035
+
2036
+
2037
+ //
2038
+ // Used in chaining. Runs a function there and then - not waiting for
2039
+ // the events to fire (eg the onbeforedraw event)
2040
+ //
2041
+ // @param function func The function to execute
2042
+ //
2043
+ this.exec = function (func)
2044
+ {
2045
+ func(this);
2046
+
2047
+ return this;
2048
+ };
2049
+
2050
+
2051
+
2052
+
2053
+
2054
+
2055
+
2056
+
2057
+ //
2058
+ // Removes the tooltip highlight from the chart
2059
+ //
2060
+ this.removeHighlight =
2061
+ this.hideHighlight = function ()
2062
+ {
2063
+ RGraph.SVG.removeHighlight();
2064
+ };
2065
+
2066
+
2067
+
2068
+
2069
+
2070
+
2071
+
2072
+
2073
+ //
2074
+ // Returns the exploded X/Y for a given explosion
2075
+ //
2076
+ //TODO Needs updating to current coding style, including converting
2077
+ // arguments to an object
2078
+ //
2079
+ this.getExploded = function (opt)
2080
+ {
2081
+ var index = opt.index,
2082
+ start = opt.start,
2083
+ end = opt.end,
2084
+ exploded = properties.exploded,
2085
+ explodedX,
2086
+ explodedY;
2087
+
2088
+ //
2089
+ // Retrieve any exploded - the exploded can be an array of numbers or a single number
2090
+ // (which is applied to all segments)
2091
+ //
2092
+ if (typeof exploded === 'object' && typeof exploded[index] === 'number') {
2093
+ explodedX = Math.cos(((end - start) / 2) + start) * exploded[index];
2094
+ explodedY = (Math.sin(((end - start) / 2) + start) * exploded[index]);
2095
+
2096
+ } else if (typeof exploded === 'number') {
2097
+ explodedX = Math.cos(((end - start) / 2) + start) * exploded;
2098
+ explodedY = Math.sin(((end - start) / 2) + start) * exploded;
2099
+
2100
+ } else {
2101
+ explodedX = 0;
2102
+ explodedY = 0;
2103
+ }
2104
+
2105
+ return [explodedX, explodedY];
2106
+ };
2107
+
2108
+
2109
+
2110
+
2111
+
2112
+
2113
+
2114
+
2115
+ //
2116
+ // The grow effect
2117
+ //
2118
+ this.grow = function (opt)
2119
+ {
2120
+ var obj = this,
2121
+ opt = arguments[0] || {},
2122
+ frame = -1,
2123
+ frames = opt.frames || 60,
2124
+ callback = opt.callback || function () {};
2125
+
2126
+ properties.effectGrowMultiplier = 0.01;
2127
+
2128
+ this.draw();
2129
+
2130
+ function iterator ()
2131
+ {
2132
+ // Increase the frame counter
2133
+ ++frame;
2134
+
2135
+ // Get the multiplier using easing
2136
+ var multiplier = RGraph.SVG.FX.getEasingMultiplier(frames, frame);
2137
+
2138
+ // Set the multiplier that the radius of the segments is
2139
+ // multiplied with.
2140
+ properties.effectGrowMultiplier = multiplier;
2141
+
2142
+ // Redraw the segments
2143
+ obj.drawRose();
2144
+
2145
+ if (frame >= frames) {
2146
+ callback(obj);
2147
+ } else {
2148
+ RGraph.SVG.FX.update(iterator);
2149
+ }
2150
+ }
2151
+
2152
+ iterator();
2153
+
2154
+ return this;
2155
+ };
2156
+
2157
+
2158
+
2159
+
2160
+
2161
+
2162
+
2163
+
2164
+ //
2165
+ // The grow effect
2166
+ //
2167
+ this.roundRobin =
2168
+ this.roundrobin = function (opt)
2169
+ {
2170
+ var obj = this,
2171
+ opt = arguments[0] || {},
2172
+ frame = -1,
2173
+ frames = opt.frames || 60,
2174
+ callback = opt.callback || function () {};
2175
+
2176
+ properties.effectRoundrobinMultiplier = 0.01;
2177
+
2178
+ this.draw();
2179
+
2180
+ function iterator ()
2181
+ {
2182
+ // Increase the frame counter
2183
+ ++frame;
2184
+
2185
+ // Get the multiplier using easing
2186
+ var multiplier = RGraph.SVG.FX.getEasingMultiplier(frames, frame);
2187
+
2188
+ // Set the multiplier that the radius of the segments is
2189
+ // multiplied with.
2190
+ properties.effectRoundrobinMultiplier = multiplier;
2191
+
2192
+ // Redraw the segments
2193
+ obj.drawRose();
2194
+
2195
+ if (frame >= frames) {
2196
+ callback(obj);
2197
+ } else {
2198
+ RGraph.SVG.FX.update(iterator);
2199
+ }
2200
+ }
2201
+
2202
+ iterator();
2203
+
2204
+ return this;
2205
+ };
2206
+
2207
+
2208
+
2209
+
2210
+
2211
+
2212
+
2213
+
2214
+ //
2215
+ // A worker function that handles Bar chart specific tooltip substitutions
2216
+ //
2217
+ this.tooltipSubstitutions = function (opt)
2218
+ {
2219
+ var indexes = RGraph.SVG.sequentialIndexToGrouped(opt.index, this.data);
2220
+
2221
+ if (properties.variant === 'non-equi-angular') {
2222
+
2223
+ // Stacked
2224
+ if (typeof this.data[0][0] === 'object') {
2225
+
2226
+ var tmp = [];
2227
+
2228
+ // Add all of the arrays to a temporary array
2229
+ for (var i=0; i<this.data.length; ++i) {
2230
+ tmp[i] = this.data[i][0];
2231
+ }
2232
+
2233
+ // Determine again the indexes
2234
+ var indexes = RGraph.SVG.sequentialIndexToGrouped(opt.index, tmp);
2235
+ var ret = {
2236
+ index: indexes[1],
2237
+ dataset: indexes[0],
2238
+ sequentialIndex: opt.index,
2239
+ value: this.data[indexes[0]][0][indexes[1]],
2240
+ value2: this.data[indexes[0]][1],
2241
+ values: this.data[indexes[0]][0]
2242
+ };
2243
+
2244
+ return ret;
2245
+
2246
+ // Non-stacked
2247
+ } else {
2248
+
2249
+ return {
2250
+ index: 0,
2251
+ dataset: opt.index,
2252
+ sequentialIndex: opt.index,
2253
+ value: (typeof this.data[opt.index] === 'object' && typeof this.data[opt.index][0] === 'number') ? this.data[opt.index][0] : mill,
2254
+ value2: (typeof this.data[opt.index] === 'object' && typeof this.data[opt.index][1] === 'number') ? this.data[opt.index][1] : null,
2255
+ values: typeof this.data[indexes[0]] === 'number' ? [this.data[indexes[0]]] : this.data[indexes[0]]
2256
+ };
2257
+ }
2258
+
2259
+ } else {
2260
+
2261
+ return {
2262
+ index: indexes[1],
2263
+ dataset: indexes[0],
2264
+ sequentialIndex: opt.index,
2265
+ value: typeof this.data[indexes[0]] === 'number' ? this.data[indexes[0]] : this.data[indexes[0]][indexes[1]],
2266
+ value2: typeof value2 === 'number' ? value2 : null,
2267
+ values: typeof this.data[indexes[0]] === 'number' ? [this.data[indexes[0]]] : this.data[indexes[0]]
2268
+ };
2269
+ }
2270
+ };
2271
+
2272
+
2273
+
2274
+
2275
+
2276
+
2277
+
2278
+
2279
+ //
2280
+ // A worker function that returns the correct color/label/value
2281
+ //
2282
+ // @param object specific The indexes that are applicable
2283
+ // @param number index The appropriate index
2284
+ //
2285
+ this.tooltipsFormattedCustom = function (specific, index, colors)
2286
+ {
2287
+ var color, label, value, value2;
2288
+
2289
+ color = properties.colors[index];
2290
+
2291
+ // Different variations of the Rose chart
2292
+
2293
+ // REGULAR CHART
2294
+ if (typeof this.data[specific.dataset] === 'number') {
2295
+ label = properties.tooltipsFormattedKeyLabels[specific.dataset] || '';
2296
+ color = !RGraph.SVG.isNull(properties.tooltipsFormattedKeyColors) && properties.tooltipsFormattedKeyColors[specific.index]
2297
+ ? properties.tooltipsFormattedKeyColors[specific.index]
2298
+ : color;
2299
+
2300
+ // NON-EQUI-ANGULAR CHART
2301
+ } else if (typeof this.data[specific.dataset] === 'object' && properties.variant === 'non-equi-angular') {
2302
+
2303
+ // REGULAT NON-EQUI-ANGULAR
2304
+ if (RGraph.SVG.isNumber(this.data[specific.dataset][0])) {
2305
+
2306
+ // Don't show the second value on a non-equi-angular chart
2307
+ if (index > 0) {
2308
+ return {continue: true};
2309
+ }
2310
+
2311
+ color = colors[specific.index];
2312
+ value = this.data[specific.dataset][0];
2313
+ value2 = typeof this.data[specific.dataset][1] === 'number' ? this.data[specific.dataset][1] : null
2314
+ label = properties.tooltipsFormattedKeyLabels[specific.dataset];//this.data[specific.dataset][0];
2315
+
2316
+ // STACKED NON-EQUI-ANGULAR
2317
+ } else if (RGraph.SVG.isArray(this.data[specific.dataset][0])) {
2318
+
2319
+ color = colors[index];
2320
+ value = this.data[specific.dataset][0][index];
2321
+ value = typeof this.data[specific.dataset][0][index] === 'number' ? this.data[specific.dataset][0][index] : null;
2322
+ value2 = typeof this.data[specific.dataset][1] === 'number' ? this.data[specific.dataset][1] : null;
2323
+ label = properties.tooltipsFormattedKeyLabels[index];
2324
+ }
2325
+ // STACKED REGULAR CHART
2326
+ } else if (typeof this.data[specific.dataset] === 'object') {
2327
+ //label = properties.tooltipsFormattedKeyLabels[specific.dataset] || '';
2328
+ color = !RGraph.SVG.isNull(properties.tooltipsFormattedKeyColors) && properties.tooltipsFormattedKeyColors[index]
2329
+ ? properties.tooltipsFormattedKeyColors[index]
2330
+ : color;
2331
+ }
2332
+
2333
+ return {
2334
+ label: label,
2335
+ color: color,
2336
+ value: value,
2337
+ value2: value2
2338
+ };
2339
+ };
2340
+
2341
+
2342
+
2343
+
2344
+
2345
+
2346
+
2347
+
2348
+ //
2349
+ // This allows for static tooltip positioning
2350
+ //
2351
+ this.positionTooltipStatic = function (args)
2352
+ {
2353
+ var obj = args.object,
2354
+ e = args.event,
2355
+ tooltip = args.tooltip,
2356
+ index = args.index,
2357
+ svgXY = RGraph.SVG.getSVGXY(obj.svg),
2358
+ angles = this.angles[index];
2359
+
2360
+ // Get the angles from the data attributes on the tag and
2361
+ // REMEMBER TO CONVERT THEM TO NUMBERS
2362
+ var startAngle = parseFloat(angles.element.getAttribute('data-start-angle'));
2363
+ var endAngle = parseFloat(angles.element.getAttribute('data-end-angle'));
2364
+ var radiusInner = parseFloat(angles.element.getAttribute('data-radius-inner'));
2365
+ var radiusOuter = parseFloat(angles.element.getAttribute('data-radius'));
2366
+ var angle = ((endAngle - startAngle) / 2) + startAngle - RGraph.SVG.TRIG.HALFPI;
2367
+
2368
+ if (isNaN(radiusInner)) {
2369
+ radiusInner = 0;
2370
+ }
2371
+
2372
+ var coords = RGraph.SVG.TRIG.toCartesian({
2373
+ cx: this.centerx,
2374
+ cy: this.centery,
2375
+ r: ((radiusOuter - radiusInner) / 2) + radiusInner,
2376
+ angle: angle
2377
+ });
2378
+
2379
+
2380
+ // Position the tooltip in the X direction
2381
+ args.tooltip.style.left = (
2382
+ svgXY[0] // The X coordinate of the canvas
2383
+ - (tooltip.offsetWidth / 2) // Subtract half of the tooltip width
2384
+ + coords.x
2385
+ ) + 'px';
2386
+
2387
+ args.tooltip.style.top = (
2388
+ svgXY[1] // The Y coordinate of the canvas
2389
+ - tooltip.offsetHeight // The height of the tooltip
2390
+ - 10 // An arbitrary amount
2391
+ + coords.y
2392
+ ) + 'px';
2393
+ };
2394
+
2395
+
2396
+
2397
+
2398
+
2399
+
2400
+
2401
+
2402
+ //
2403
+ // Set the options that the user has provided
2404
+ //
2405
+ for (i in conf.options) {
2406
+ if (typeof i === 'string') {
2407
+ this.set(i, conf.options[i]);
2408
+ }
2409
+ }
2410
+ };
2411
+
2412
+
2413
+
2414
+ return this;
2415
+
2416
+
2417
+
2418
+
2419
+ // End module pattern
2420
+ })(window, document);