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,59 +1,1773 @@
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.Radar=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='radar';this.coords=[];this.coords2=[];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,backgroundGrid:true,backgroundGridColor:'#ddd',backgroundGridRadialsCount:null,backgroundGridConcentricsCount:5,backgroundGridLinewidth:1,backgroundGridPoly:true,colors:['red','black','orange','green','#6ff','#ccc','pink','orange','cyan','maroon','olive','teal'],filled:false,filledOpacity:0.25,filledAccumulative:true,textColor:'black',textFont:'Arial, Verdana, sans-serif',textSize:12,textBold:false,textItalic:false,labels:[],labelsFont:null,labelsColor:null,labelsSize:null,labelsBold:null,labelsItalic:null,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:'mousemove',highlightStroke:'rgba(0,0,0,0)',highlightFill:'rgba(255,255,255,0.7)',highlightLinewidth:1,tickmarksStyle:'circle',tickmarksLinewidth:1,tickmarksSize:6,tickmarksFill:'white',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,key:null,keyColors:null,keyOffsetx:0,keyOffsety:0,keyLabelsOffsetx:0,keyLabelsOffsety:-1,keyLabelsSize:null,keyLabelsBold:null,keyLabelsItalic:null,keyLabelsFont:null,keyLabelsColor:null};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);if(this.data.length>1){var len=this.data[0].length;for(var i=1;i<this.data.length;++i){if(this.data[i].length!==len){alert('[ERROR] The Radar chart datasets must have the same number of elements!');}}}
10
- this.angles=[];this.angles2=[];this.coords=[];this.coords2=[];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(RG.SVG.isArray(this.data)&&(typeof this.data[0]==='number'||typeof this.data[0]==='string')){this.data=[this.data];}
11
- for(var i=0;i<this.data.length;++i){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]);}}}
12
- if(prop.filled&&prop.filledAccumulative){for(var dataset=1;dataset<this.data.length;++dataset){for(var i=0;i<this.data[dataset].length;++i){this.data[dataset][i]+=this.data[dataset-1][i];}}}
13
- 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.drawRadar();this.drawTickmarks();this.drawLabels();RG.SVG.drawTitle(this);this.addTooltipHotspots();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?');}
14
- RG.SVG.attribution(this);if(prop.shadow){RG.SVG.setShadow({object:this,offsetx:prop.shadowOffsetx,offsety:prop.shadowOffsety,blur:prop.shadowBlur,opacity:prop.shadowOpacity,id:'dropShadow'});}
15
- var obj=this;doc.body.addEventListener('mousedown',function(e)
16
- {obj.hideHighlight(obj);},false);RG.SVG.fireCustomEvent(this,'ondraw');return this;};this.drawBackground=function()
17
- {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}});var origin=0-(RG.SVG.TRIG.PI/2),radials=(typeof prop.backgroundGridRadialsCount==='number'?prop.backgroundGridRadialsCount:this.data[0].length),concentrics=prop.backgroundGridConcentricsCount,step=RG.SVG.TRIG.TWOPI/radials;if(radials>0){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)});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){if(prop.backgroundGridPoly){for(var j=1;j<=concentrics;j++){for(var i=0,len=radials,path=[];i<len;++i){var coords=RG.SVG.TRIG.toCartesian({cx:this.centerx,cy:this.centery,r:this.radius*(j/concentrics),angle:origin+(i*step)});path.push('{1} {2} {3}'.format(i===0?'M':'L',coords.x,coords.y));}
19
- RG.SVG.create({svg:this.svg,type:'path',parent:grid,attr:{d:path.join(' ')+' z',fill:'transparent',stroke:prop.backgroundGridColor,'stroke-width':prop.backgroundGridLinewidth}});}}else{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.drawRadar=function(opt)
20
- {for(var dataset=0,len=this.data.length;dataset<len;++dataset){this.coords2[dataset]=[];this.angles2[dataset]=[];var path=[];for(var i=0,len2=this.data[dataset].length;i<len2;++i){var value=this.data[dataset][i];var xy=RG.SVG.TRIG.toCartesian({cx:this.centerx,cy:this.centery,r:this.getRadius(this.data[dataset][i]),angle:(RG.SVG.TRIG.TWOPI/len2)*i-RG.SVG.TRIG.HALFPI});xy.r=(((value-prop.scaleMin)/(this.max-prop.scaleMin)))*this.radius;xy.angle=(RG.SVG.TRIG.TWOPI/len2)*i-RG.SVG.TRIG.HALFPI;path.push('{1}{2} {3}'.format(i===0?'M':'L',xy.x,xy.y));this.angles.push({object:this,dataset:dataset,index:i,x:xy.x,y:xy.y,cx:this.centerx,cy:this.centery,r:xy.r,angle:xy.angle});this.angles2[dataset].push({object:this,dataset:dataset,index:i,x:xy.x,y:xy.y,cx:this.centerx,cy:this.centery,r:xy.r,angle:xy.angle});this.coords.push([xy.x,xy.y]);this.coords2[dataset].push([xy.x,xy.y]);}
21
- if(dataset>0&&prop.filled&&prop.filledAccumulative){path.push('L {1} {2}'.format(this.coords2[dataset][0][0],this.coords2[dataset][0][1]));path.push('M {1} {2}'.format(this.coords2[dataset-1][0][0],this.coords2[dataset-1][0][1]));for(var i=this.coords2[dataset-1].length-1;i>=0;--i){path.push('L {1} {2}'.format(this.coords2[dataset-1][i][0],this.coords2[dataset-1][i][1]));}
22
- this.redraw=true;}else{path.push('z');}
23
- var path=RG.SVG.create({svg:this.svg,type:'path',parent:this.svg.all,attr:{d:path.join(" "),stroke:prop.colors[dataset],fill:prop.filled?prop.colors[dataset]:'transparent','fill-opacity':prop.filledOpacity,'stroke-width':prop.linewidth,'clip-path':this.isTrace?'url(#trace-effect-clip)':'',filter:prop.shadow?'url(#dropShadow)':'',}});path.setAttribute('data-dataset',dataset);}
24
- this.redrawRadar();};this.redrawRadar=function()
25
- {if(this.redraw){this.redraw=false;for(var dataset=0;dataset<this.coords2.length;++dataset){var path=[];for(var i=0;i<this.coords2[dataset].length;++i){if(i===0){path.push('M {1} {2}'.format(this.coords2[dataset][i][0],this.coords2[dataset][i][1]));}else{path.push('L {1} {2}'.format(this.coords2[dataset][i][0],this.coords2[dataset][i][1]))}}
26
- path.push('z')
27
- RG.SVG.create({svg:this.svg,type:'path',parent:this.svg.all,attr:{d:path.join(" "),stroke:prop.colors[dataset],fill:'transparent','stroke-width':prop.linewidth}});}}};this.drawTickmarks=function()
28
- {var group=RG.SVG.create({svg:this.svg,parent:this.svg.all,type:'g',attr:{className:'rgraph_radar_tickmarks'}});for(var i=0;i<this.coords2.length;++i){for(var j=0;j<this.coords2[i].length;++j){if(prop.tickmarksStyle==='circle'||prop.tickmarksStyle==='filledcircle'){var c=RG.SVG.create({svg:this.svg,type:'circle',parent:group,attr:{cx:this.coords2[i][j][0],cy:this.coords2[i][j][1],r:prop.tickmarksSize,fill:prop.tickmarksStyle==='filledcircle'?prop.colors[i]:prop.tickmarksFill,stroke:prop.colors[i],'stroke-width':prop.tickmarksLinewidth,'clip-path':this.isTrace?'url(#trace-effect-clip)':''}});c.setAttribute('data-dataset',i);c.setAttribute('data-index',j);}else if(prop.tickmarksStyle==='rect'||prop.tickmarksStyle==='filledrect'){var halfTickmarkSize=prop.tickmarksSize/2;var fill=typeof prop.tickmarksFill==='object'&&prop.tickmarksFill[i]?prop.tickmarksFill[i]:prop.tickmarksFill;var s=RG.SVG.create({svg:this.svg,type:'rect',parent:group,attr:{x:this.coords2[i][j][0]-halfTickmarkSize,y:this.coords2[i][j][1]-halfTickmarkSize,width:prop.tickmarksSize,height:prop.tickmarksSize,fill:prop.tickmarksStyle==='filledrect'?prop.colors[i]:fill,stroke:prop.colors[i],'stroke-width':prop.tickmarksLinewidth}});s.setAttribute('data-dataset',i);s.setAttribute('data-index',j);}}}};this.drawLabels=function()
29
- {var angles=this.angles2,prop=this.properties,labels=prop.labels;for(var i=0,len=labels.length;i<len;++i){if(!labels[i]){continue;}
30
- var endpoint=RG.SVG.TRIG.getRadiusEndPoint({angle:RG.SVG.TRIG.TWOPI/labels.length*i-RG.SVG.TRIG.HALFPI,r:this.radius+15});var x=endpoint[0]+this.centerx,y=endpoint[1]+this.centery;if((i/len)<0.5){halign='left';}else{halign='right';}
31
- if((i/len)<0.25||(i/len)>0.75){valign='bottom';}else{valign='top';}
32
- if((i/len)===0){halign='center';}
33
- if((i/len)===0.25){valign='center';}
34
- if((i/len)===0.5){halign='center';}
35
- if((i/len)===0.75){valign='center';}
36
- RG.SVG.text({object:this,svg:this.svg,parent:this.svg.all,tag:'labels',text:labels[i],x:x,y:y,halign:halign,valign:'center',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});}
37
- if(prop.scaleVisible){for(var i=0;i<this.scale.labels.length;++i){var x=this.centerx;var y=this.centery-(this.radius/this.scale.labels.length*(i+1));RG.SVG.text({object:this,svg:this.svg,parent:this.svg.all,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});}
38
- 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:this.svg.all,tag:'labels.scale',text:str,x:this.centerx,y:this.centery,halign:'center',valign:'center',background:'rgba(255,255,255,0.7)',padding:2,color:prop.scaleColor||prop.textColor,size:typeof prop.scaleSize==='number'?prop.scaleSize:prop.textSize-2,bold:typeof prop.scaleBold==='boolean'?prop.scaleBold:prop.textBold,italic:typeof prop.scaleItalic==='boolean'?prop.scaleItalic:prop.textItalic,font:prop.scaleFont||prop.textFont});}};this.highlight=function(circle)
39
- {circle.setAttribute('fill',prop.highlightFill);circle.setAttribute('stroke',prop.highlightStroke);circle.setAttribute('stroke-width',prop.highlightLinewidth);this.highlight_node=circle;RG.SVG.REG.set('highlight',circle);};this.parseColors=function()
40
- {if(!Object.keys(this.originalColors).length){this.originalColors={colors:RG.SVG.arrayClone(prop.colors),highlightFill:RG.SVG.arrayClone(prop.highlightFill)}}
41
- var colors=prop.colors;if(colors){for(var i=0;i<colors.length;++i){colors[i]=RG.SVG.parseColorRadial({object:this,color:colors[i]});}}
42
- prop.highlightFill=RG.SVG.parseColorRadial({object:this,color:prop.highlightFill});};this.getMaxValue=function()
43
- {var max=0;if(prop.filled&&prop.filledAccumulative){this.max=RG.SVG.arrayMax(this.data[this.data.length-1]);}else{for(var dataset=0,max=0;dataset<this.data.length;++dataset){this.max=ma.max(this.max,RG.SVG.arrayMax(this.data[dataset]));}}};this.getRadius=function(value)
44
- {return((value-prop.scaleMin)/(this.scale.max-prop.scaleMin))*this.radius;};this.addTooltipHotspots=function()
45
- {if(prop.tooltips&&prop.tooltips.length>0){if(prop.tooltipsEvent!=='mousemove'){prop.tooltipsEvent='click';}
46
- var group=RG.SVG.create({svg:this.svg,type:'g',parent:this.svg.all,attr:{className:'rgraph-radar-tooltip-hotspots'}});for(var dataset=0,seq=0;dataset<this.coords2.length;++dataset){for(var i=0;i<this.coords2[dataset].length;++i){var circle=RG.SVG.create({svg:this.svg,type:'circle',parent:group,attr:{cx:this.coords2[dataset][i][0],cy:this.coords2[dataset][i][1],r:prop.tickmarksSize,fill:'transparent',stroke:'transparent','stroke-width':0,'data-sequential-index':seq},style:{cursor:prop['tooltips'][seq]?'pointer':'default'}});(function(dataset,index,seq,obj)
47
- {if(prop.tooltips[seq]){circle.addEventListener(prop.tooltipsEvent,function(e)
48
- {var tooltip=RG.SVG.REG.get('tooltip');if(tooltip&&tooltip.__sequentialIndex__===seq){return;}
49
- RG.SVG.tooltip({object:obj,dataset:dataset,index:index,sequentialIndex:seq,text:prop.tooltips[seq],event:e});obj.highlight(this);},false);if(prop.tooltipsEvent==='click'){circle.addEventListener('mousemove',function(e)
50
- {e.target.style.cursor='pointer';},false);}}}(dataset,i,seq++,this));}}}};this.roundRobin=function()
51
- {};this.on=function(type,func)
52
- {if(type.substr(0,2)!=='on'){type='on'+type;}
53
- RG.SVG.addCustomEventListener(this,type,func);return this;};this.exec=function(func)
54
- {func(this);return this;};this.removeHighlight=this.hideHighlight=function()
55
- {var highlight=RG.SVG.REG.get('highlight');if(highlight&&this.highlight_node){this.highlight_node.setAttribute('fill','transparent');this.highlight_node.setAttribute('stroke','transparent');RG.SVG.REG.set('highlight',null);}};this.trace=function()
56
- {var opt=arguments[0]||{},frame=1,frames=opt.frames||120,obj=this
57
- step=360/frames;this.isTrace=true;this.draw();var clipPath=RG.SVG.create({svg:this.svg,parent:this.svg.defs,type:'clipPath',attr:{id:'trace-effect-clip'}});clipPathArcPath=RG.SVG.TRIG.getArcPath2({cx:this.angles[0].cx,cy:this.angles[0].cy,r:this.angles[0].r*2,start:0,end:0});var clipPathArc=RG.SVG.create({svg:this.svg,parent:clipPath,type:'path',attr:{d:clipPathArcPath}});var iterator=function()
58
- {var width=(frame++)/frames*obj.width;var deg=(360/frames)*frame++,rad=(RG.SVG.TRIG.TWOPI/360)*deg
59
- clipPathArc.setAttribute('d',RG.SVG.TRIG.getArcPath2({cx:obj.angles[0].cx,cy:obj.angles[0].cy,r:obj.angles[0].r*2,start:0,end:rad}));if(frame<=frames){RG.SVG.FX.update(iterator);}else if(opt.callback){(opt.callback)(obj);}};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.Radar = 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
+ this.id = conf.id;
89
+ this.uid = RGraph.SVG.createUID();
90
+ this.container = document.getElementById(this.id);
91
+ this.layers = {}; // MUST be before the SVG tag is created!
92
+ this.svg = RGraph.SVG.createSVG({object: this,container: this.container});
93
+ this.isRGraph = true;
94
+ this.isrgraph = true;
95
+ this.rgraph = true;
96
+ this.width = Number(this.svg.getAttribute('width'));
97
+ this.height = Number(this.svg.getAttribute('height'));
98
+ this.data = RGraph.SVG.arrayClone(conf.data);
99
+ this.originalData = RGraph.SVG.arrayClone(conf.data);
100
+ this.type = 'radar';
101
+ this.coords = [];
102
+ this.coords2 = [];
103
+ this.angles = [];
104
+ this.angles2 = [];
105
+ this.colorsParsed = false;
106
+ this.originalColors = {};
107
+ this.gradientCounter = 1;
108
+ this.nodes = [];
109
+ this.shadowNodes = [];
110
+ this.max = 0;
111
+ this.redraw = false;
112
+ this.highlight_node = null;
113
+ this.firstDraw = true; // After the first draw this will be false
114
+
115
+ // Convert the data to numbers in case they're passed in as strings
116
+ this.originalData = RGraph.SVG.stringsToNumbers(this.originalData);
117
+
118
+ //The originalData array should be a multi-dimensional array of each dataset, even if
119
+ // there's only one dataset
120
+ if (typeof this.originalData[0] === 'number') {
121
+ this.originalData = [this.originalData];
122
+ }
123
+
124
+
125
+
126
+
127
+
128
+
129
+
130
+ // Add this object to the ObjectRegistry
131
+ RGraph.SVG.OR.add(this);
132
+
133
+ // Set the DIV container to be inline-block
134
+ this.container.style.display = 'inline-block';
135
+
136
+
137
+
138
+
139
+
140
+ this.properties =
141
+ {
142
+ centerx: null,
143
+ centery: null,
144
+ radius: null,
145
+
146
+ marginLeft: 35,
147
+ marginRight: 35,
148
+ marginTop: 35,
149
+ marginBottom: 35,
150
+
151
+ backgroundGrid: true,
152
+ backgroundGridColor: '#ddd',
153
+ backgroundGridRadialsCount: null,
154
+ backgroundGridConcentricsCount: 5,
155
+ backgroundGridLinewidth: 1,
156
+ backgroundGridPoly: true,
157
+
158
+ colors: [
159
+ 'red', 'black', 'orange', 'green', '#6ff', '#ccc',
160
+ 'pink', 'orange', 'cyan', 'maroon', 'olive', 'teal'
161
+ ],
162
+ filled: false,
163
+ filledOpacity: 0.25,
164
+ filledAccumulative: true,
165
+
166
+ textColor: 'black',
167
+ textFont: 'Arial, Verdana, sans-serif',
168
+ textSize: 12,
169
+ textBold: false,
170
+ textItalic: false,
171
+ text: null,
172
+
173
+ labels: [],
174
+ labelsFont: null,
175
+ labelsColor: null,
176
+ labelsSize: null,
177
+ labelsBold: null,
178
+ labelsItalic: null,
179
+ labelsOffset: 0,
180
+ labelsFormattedDecimals: 0,
181
+ labelsFormattedPoint: '.',
182
+ labelsFormattedThousand: ',',
183
+ labelsFormattedUnitsPre: '',
184
+ labelsFormattedUnitsPost: '',
185
+
186
+ scaleVisible: true,
187
+ scaleUnitsPre: '',
188
+ scaleUnitsPost: '',
189
+ scaleMax: null,
190
+ scaleMin: 0,
191
+ scalePoint: '.',
192
+ scaleThousand: ',',
193
+ scaleRound: false,
194
+ scaleDecimals: 0,
195
+ scaleFormatter: null,
196
+ scaleBold: null,
197
+ scaleItalic: null,
198
+ scaleColor: null,
199
+ scaleSize: null,
200
+ scaleFont: null,
201
+ scaleLabelsCount: 5,
202
+
203
+ linewidth: 1,
204
+
205
+ tooltips: null,
206
+ tooltipsOverride: null,
207
+ tooltipsEffect: 'fade',
208
+ tooltipsCssClass: 'RGraph_tooltip',
209
+ tooltipsCss: null,
210
+ tooltipsEvent: 'mousemove',
211
+ tooltipsFormattedThousand: ',',
212
+ tooltipsFormattedPoint: '.',
213
+ tooltipsFormattedDecimals: 0,
214
+ tooltipsFormattedUnitsPre: '',
215
+ tooltipsFormattedUnitsPost: '',
216
+ tooltipsFormattedKeyColors: null,
217
+ tooltipsFormattedKeyColorsShape: 'square',
218
+ tooltipsFormattedKeyLabels: [],
219
+ tooltipsFormattedTableHeaders: null,
220
+ tooltipsFormattedTableData: null,
221
+ tooltipsPointer: true,
222
+ tooltipsPointerOffsetx: 0,
223
+ tooltipsPointerOffsety: 0,
224
+ tooltipsPositionStatic: true,
225
+
226
+ highlightStroke: 'rgba(0,0,0,0)',
227
+ highlightFill: 'rgba(255,255,255,0.7)',
228
+ highlightLinewidth: 1,
229
+
230
+ tickmarksStyle: 'circle',
231
+ tickmarksLinewidth: 1,
232
+ tickmarksSize: 6,
233
+ tickmarksFill: 'white',
234
+
235
+ title: '',
236
+ titleX: null,
237
+ titleY: null,
238
+ titleHalign: 'center',
239
+ titleValign: null,
240
+ titleSize: null,
241
+ titleColor: null,
242
+ titleFont: null,
243
+ titleBold: null,
244
+ titleItalic: null,
245
+
246
+ titleSubtitle: null,
247
+ titleSubtitleSize: null,
248
+ titleSubtitleColor: '#aaa',
249
+ titleSubtitleFont: null,
250
+ titleSubtitleBold: null,
251
+ titleSubtitleItalic: null,
252
+
253
+ shadow: false,
254
+ shadowOffsetx: 2,
255
+ shadowOffsety: 2,
256
+ shadowBlur: 2,
257
+ shadowColor: 'rgba(0,0,0,0.25)',
258
+
259
+
260
+
261
+ key: null,
262
+ keyColors: null,
263
+ keyOffsetx: 0,
264
+ keyOffsety: 0,
265
+ keyLabelsOffsetx: 0,
266
+ keyLabelsOffsety: -1,
267
+ keyLabelsSize: null,
268
+ keyLabelsBold: null,
269
+ keyLabelsItalic: null,
270
+ keyLabelsFont: null,
271
+ keyLabelsColor: null
272
+ };
273
+
274
+
275
+
276
+
277
+ //
278
+ // Copy the global object properties to this instance
279
+ //
280
+ RGraph.SVG.getGlobals(this);
281
+
282
+
283
+
284
+
285
+
286
+
287
+ //
288
+ // "Decorate" the object with the generic effects if the effects library has been included
289
+ //
290
+ if (RGraph.SVG.FX && typeof RGraph.SVG.FX.decorate === 'function') {
291
+ RGraph.SVG.FX.decorate(this);
292
+ }
293
+
294
+
295
+
296
+
297
+
298
+ // Add the responsive function to the object
299
+ this.responsive = RGraph.SVG.responsive;
300
+
301
+
302
+
303
+
304
+ var properties = this.properties;
305
+
306
+
307
+
308
+
309
+
310
+
311
+
312
+
313
+ //
314
+ // The draw method draws the Bar chart
315
+ //
316
+ this.draw = function ()
317
+ {
318
+ // Fire the beforedraw event
319
+ RGraph.SVG.fireCustomEvent(this, 'onbeforedraw');
320
+
321
+
322
+
323
+
324
+
325
+
326
+
327
+
328
+
329
+
330
+
331
+
332
+
333
+
334
+
335
+
336
+ // Should the first thing that's done inthe.draw() function
337
+ // except for the onbeforedraw event
338
+ this.width = Number(this.svg.getAttribute('width'));
339
+ this.height = Number(this.svg.getAttribute('height'));
340
+
341
+
342
+
343
+
344
+
345
+
346
+
347
+
348
+
349
+
350
+
351
+
352
+ // Reset the data back to the original values
353
+ this.data = RGraph.SVG.arrayClone(this.originalData);
354
+
355
+ //
356
+ // The datasets have to have the same number of elements
357
+ //
358
+ if (this.data.length > 1) {
359
+
360
+ var len = this.data[0].length;
361
+
362
+ for (var i=1; i<this.data.length; ++i) {
363
+ if (this.data[i].length !== len) {
364
+ alert('[ERROR] The Radar chart datasets must have the same number of elements!');
365
+ }
366
+ }
367
+ }
368
+
369
+
370
+
371
+ // Reset the coords array to stop them growing
372
+ this.angles = [];
373
+ this.angles2 = [];
374
+ this.coords = [];
375
+ this.coords2 = [];
376
+
377
+
378
+
379
+
380
+
381
+ // Create the defs tag if necessary
382
+ RGraph.SVG.createDefs(this);
383
+
384
+
385
+
386
+
387
+ this.graphWidth = this.width - properties.marginLeft - properties.marginRight;
388
+ this.graphHeight = this.height - properties.marginTop - properties.marginBottom;
389
+
390
+
391
+
392
+ // Work out the center point
393
+ this.centerx = (this.graphWidth / 2) + properties.marginLeft;
394
+ this.centery = (this.graphHeight / 2) + properties.marginTop;
395
+ this.radius = Math.min(this.graphWidth, this.graphHeight) / 2;
396
+
397
+
398
+
399
+ // Allow the user to override the calculated centerx/y/radius
400
+ this.centerx = typeof properties.centerx === 'number' ? properties.centerx : this.centerx;
401
+ this.centery = typeof properties.centery === 'number' ? properties.centery : this.centery;
402
+ this.radius = typeof properties.radius === 'number' ? properties.radius : this.radius;
403
+
404
+ //
405
+ // Allow the centerx/centery/radius to be a plus/minus
406
+ //
407
+ if (typeof properties.radius === 'string' && properties.radius.match(/^\+|-\d+$/) ) this.radius += parseFloat(properties.radius);
408
+ if (typeof properties.centerx === 'string' && properties.centerx.match(/^\+|-\d+$/) ) this.centery += parseFloat(properties.centerx);
409
+ if (typeof properties.centery === 'string' && properties.centery.match(/^\+|-\d+$/) ) this.centerx += parseFloat(properties.centery);
410
+
411
+
412
+
413
+
414
+
415
+ //
416
+ // Add the data to the .originalData array and work out the max value
417
+ //
418
+ // 2/5/14 Now also use this loop to ensure that the data pieces
419
+ // are numbers
420
+ //
421
+ if (RGraph.SVG.isArray(this.data) && (typeof this.data[0] === 'number' || typeof this.data[0] === 'string')) {
422
+ this.data = [this.data];
423
+ }
424
+
425
+ // Convert strings to numbers
426
+ for (var i=0; i<this.data.length; ++i) {
427
+
428
+ for (var j=0; j<this.data[i].length; ++j) {
429
+
430
+ if (typeof this.data[i][j] === 'string') {
431
+ this.data[i][j] = RGraph.SVG.stringsToNumbers(this.data[i][j]);
432
+ }
433
+ }
434
+ }
435
+
436
+
437
+
438
+
439
+
440
+
441
+ // Modify the datasets to represent the stacked data
442
+ // (if its stacked)
443
+ if (properties.filled && properties.filledAccumulative) {
444
+ for (var dataset=1; dataset<this.data.length; ++dataset) {
445
+ for (var i=0; i<this.data[dataset].length; ++i) {
446
+ this.data[dataset][i] += this.data[dataset - 1][i];
447
+ }
448
+ }
449
+ }
450
+
451
+
452
+
453
+
454
+
455
+ // Get the max value
456
+ this.getMaxValue();
457
+
458
+
459
+
460
+
461
+
462
+
463
+
464
+ // Parse the colors for gradients
465
+ RGraph.SVG.resetColorsToOriginalValues({object:this});
466
+ this.parseColors();
467
+
468
+ //
469
+ // Get the scale
470
+ //
471
+
472
+ this.scale = RGraph.SVG.getScale({
473
+ object: this,
474
+ numlabels: typeof properties.scaleLabelsCount === 'number' ? properties.scaleLabelsCount : properties.backgroundGridConcentricCount,
475
+ unitsPre: properties.scaleUnitsPre,
476
+ unitsPost: properties.scaleUnitsPost,
477
+ max: typeof properties.scaleMax === 'number' ? properties.scaleMax : this.max,
478
+ min: properties.scaleMin,
479
+ point: properties.scalePoint,
480
+ round: properties.scaleRound,
481
+ thousand: properties.scaleThousand,
482
+ decimals: properties.scaleDecimals,
483
+ strict: typeof properties.scaleMax === 'number',
484
+ formatter: properties.scaleFormatter
485
+ });
486
+
487
+ this.max = this.scale.max;
488
+
489
+
490
+
491
+ // Draw the background 'grid'
492
+ this.drawBackground();
493
+
494
+
495
+
496
+ // Draw the chart
497
+ this.drawRadar();
498
+
499
+
500
+
501
+ // Draw the tickmarks for the chart
502
+ this.drawTickmarks();
503
+
504
+
505
+
506
+ // Draw the labels
507
+ this.drawLabels();
508
+
509
+
510
+
511
+ // Draw the title and subtitle
512
+ RGraph.SVG.drawTitle(this);
513
+
514
+
515
+
516
+ // Add the tooltip hotspots
517
+ this.addTooltipHotspots();
518
+
519
+
520
+
521
+
522
+
523
+
524
+ // Draw the key
525
+ if (typeof properties.key !== null && RGraph.SVG.drawKey) {
526
+ RGraph.SVG.drawKey(this);
527
+ } else if (!RGraph.SVG.isNull(properties.key)) {
528
+ alert('The drawKey() function does not exist - have you forgotten to include the key library?');
529
+ }
530
+
531
+
532
+
533
+
534
+
535
+ // Add the attribution link. If you're adding this elsewhere on your page/site
536
+ // and you don't want it displayed then there are options available to not
537
+ // show it.
538
+ RGraph.SVG.attribution(this);
539
+
540
+ // Create the shadow definition if needed
541
+ if (properties.shadow) {
542
+ RGraph.SVG.setShadow({
543
+ object: this,
544
+ offsetx: properties.shadowOffsetx,
545
+ offsety: properties.shadowOffsety,
546
+ blur: properties.shadowBlur,
547
+ color: properties.shadowColor,
548
+ id: 'dropShadow'
549
+ });
550
+ }
551
+
552
+
553
+
554
+ // Add the event listener that clears the highlight if
555
+ // there is any. Must be MOUSEDOWN (ie before the click event)
556
+ var obj = this;
557
+ document.body.addEventListener('mousedown', function (e)
558
+ {
559
+ obj.removeHighlight();
560
+ }, false);
561
+
562
+
563
+
564
+
565
+
566
+
567
+
568
+
569
+ //
570
+ // Allow the addition of custom text via the
571
+ // text: property.
572
+ //
573
+ RGraph.SVG.addCustomText(this);
574
+
575
+
576
+
577
+
578
+
579
+
580
+
581
+
582
+
583
+
584
+
585
+
586
+
587
+ //
588
+ // Fire the onfirstdraw event
589
+ //
590
+ if (this.firstDraw) {
591
+ this.firstDraw = false;
592
+ RGraph.SVG.fireCustomEvent(this, 'onfirstdraw');
593
+ }
594
+
595
+
596
+
597
+
598
+
599
+ // Fire the draw event
600
+ RGraph.SVG.fireCustomEvent(this, 'ondraw');
601
+
602
+
603
+
604
+
605
+
606
+
607
+
608
+ //
609
+ // Install any inline responsive configuration. This
610
+ // should be last in the draw function - even after
611
+ // the draw events.
612
+ //
613
+ RGraph.SVG.installInlineResponsive(this);
614
+
615
+
616
+
617
+
618
+
619
+
620
+
621
+
622
+
623
+
624
+
625
+ return this;
626
+ };
627
+
628
+
629
+
630
+
631
+
632
+
633
+
634
+
635
+ //
636
+ // New create() shortcut function
637
+ // For example:
638
+ // this.create('rect,x:0,y:0,width:100,height:100'[,parent]);
639
+ //
640
+ // @param str string The tag definition to parse and create
641
+ // @param object The (optional) parent element
642
+ // @return object The new tag
643
+ //
644
+ this.create = function (str)
645
+ {
646
+ var def = RGraph.SVG.create.parseStr(this, str);
647
+ def.svg = this.svg;
648
+
649
+ // By default the parent is the SVG tag - but if
650
+ // requested then change it to the tag that has
651
+ // been given
652
+ if (arguments[1]) {
653
+ def.parent = arguments[1];
654
+ }
655
+
656
+ return RGraph.SVG.create(def);
657
+ };
658
+
659
+
660
+
661
+
662
+
663
+
664
+
665
+
666
+ //
667
+ // Draw the background grid
668
+ //
669
+ this.drawBackground = function ()
670
+ {
671
+ if (properties.backgroundGrid) {
672
+
673
+ // Create the background grid group tag
674
+ var grid = RGraph.SVG.create({
675
+ svg: this.svg,
676
+ parent: this.svg.all,
677
+ type: 'g',
678
+ attr: {
679
+ className: 'rgraph_radar_grid',
680
+ fill: 'rgba(0,0,0,0)',
681
+ stroke: properties.backgroundGridColor
682
+ }
683
+ });
684
+
685
+ // Draw the concentric "rings" grid lines that are
686
+ // arranged around the centerx/centery along with
687
+ // the radials that eminate from the center outwards
688
+
689
+ var origin = 0 - (RGraph.SVG.TRIG.PI / 2),
690
+ radials = (typeof properties.backgroundGridRadialsCount === 'number' ? properties.backgroundGridRadialsCount : this.data[0].length),
691
+ concentrics = properties.backgroundGridConcentricsCount,
692
+ step = RGraph.SVG.TRIG.TWOPI / radials;
693
+
694
+
695
+
696
+
697
+
698
+ // First draw the radial lines that emanate from the
699
+ // center outwards
700
+ if (radials > 0) {
701
+
702
+ for (var i=0,len=radials; i<len; ++i) {
703
+
704
+ var coords = RGraph.SVG.TRIG.toCartesian({
705
+ cx: this.centerx,
706
+ cy: this.centery,
707
+ r: this.radius,
708
+ angle: origin + (i * step)
709
+ });
710
+
711
+ var str = 'M {1} {2} L {3} {4}'.format(
712
+ this.centerx,
713
+ this.centery,
714
+ coords.x,
715
+ coords.y
716
+ );
717
+
718
+ RGraph.SVG.create({
719
+ svg: this.svg,
720
+ type: 'path',
721
+ parent: grid,
722
+ attr: {
723
+ d: str,
724
+ stroke: properties.backgroundGridColor,
725
+ 'stroke-width': properties.backgroundGridLinewidth
726
+ }
727
+ });
728
+ }
729
+ }
730
+
731
+
732
+
733
+
734
+
735
+ // Draw the concentrics
736
+ if (concentrics > 0) {
737
+
738
+ if (properties.backgroundGridPoly) {
739
+ for (var j=1; j<=concentrics; j++) {
740
+ for (var i=0,len=radials,path=[]; i<len; ++i) {
741
+
742
+ var coords = RGraph.SVG.TRIG.toCartesian({
743
+ cx: this.centerx,
744
+ cy: this.centery,
745
+ r: this.radius * (j/concentrics),
746
+ angle: origin + (i * step)
747
+ });
748
+
749
+ path.push('{1} {2} {3}'.format(
750
+ i === 0 ? 'M' : 'L',
751
+ coords.x,
752
+ coords.y
753
+ ));
754
+
755
+ }
756
+
757
+ // Now add the path to the scene
758
+ RGraph.SVG.create({
759
+ svg: this.svg,
760
+ type: 'path',
761
+ parent: grid,
762
+ attr: {
763
+ d: path.join(' ') + ' z',
764
+ fill: 'transparent',
765
+ stroke: properties.backgroundGridColor,
766
+ 'stroke-width': properties.backgroundGridLinewidth
767
+ }
768
+ });
769
+ }
770
+
771
+
772
+
773
+
774
+
775
+ // Draw the background "grid" as concentric circles
776
+ } else {
777
+
778
+
779
+
780
+
781
+
782
+
783
+ for (var j=1; j<=concentrics; j++) {
784
+
785
+ // Add circle to the scene
786
+ RGraph.SVG.create({
787
+ svg: this.svg,
788
+ type: 'circle',
789
+ parent: grid,
790
+ attr: {
791
+ cx: this.centerx,
792
+ cy: this.centery,
793
+ r: this.radius * (j/concentrics),
794
+ fill: 'transparent',
795
+ stroke: properties.backgroundGridColor,
796
+ 'stroke-width': properties.backgroundGridLinewidth
797
+ }
798
+ });
799
+ }
800
+ }
801
+ }
802
+ }
803
+ };
804
+
805
+
806
+
807
+
808
+
809
+
810
+
811
+
812
+ //
813
+ // Draws the radar
814
+ //
815
+ this.drawRadar = function (opt)
816
+ {
817
+ for (var dataset=0,len=this.data.length; dataset<len; ++dataset) {
818
+
819
+ // Ensure these exist
820
+ this.coords2[dataset] = [];
821
+ this.angles2[dataset] = [];
822
+
823
+ // Initialise the path
824
+ var path = [];
825
+
826
+ for (var i=0,len2=this.data[dataset].length; i<len2; ++i) {
827
+
828
+ var value = this.data[dataset][i];
829
+
830
+ var xy = RGraph.SVG.TRIG.toCartesian({
831
+ cx: this.centerx,
832
+ cy: this.centery,
833
+ r: this.getRadius(this.data[dataset][i]),
834
+ angle: (RGraph.SVG.TRIG.TWOPI / len2) * i - RGraph.SVG.TRIG.HALFPI
835
+ });
836
+
837
+ xy.r = (( (value - properties.scaleMin) / (this.max - properties.scaleMin) ) ) * this.radius;
838
+ xy.angle = (RGraph.SVG.TRIG.TWOPI / len2) * i - RGraph.SVG.TRIG.HALFPI;
839
+
840
+ path.push('{1}{2} {3}'.format(
841
+ i === 0 ? 'M' : 'L',
842
+ xy.x,
843
+ xy.y
844
+ ));
845
+
846
+ // Save the coordinates and angle
847
+ this.angles.push({
848
+ object: this,
849
+ dataset: dataset,
850
+ index: i,
851
+ x: xy.x,
852
+ y: xy.y,
853
+ cx: this.centerx,
854
+ cy: this.centery,
855
+ r: xy.r,
856
+ angle: xy.angle
857
+ });
858
+ this.angles2[dataset].push({
859
+ object: this,
860
+ dataset: dataset,
861
+ index: i,
862
+ x: xy.x,
863
+ y: xy.y,
864
+ cx: this.centerx,
865
+ cy: this.centery,
866
+ r: xy.r,
867
+ angle: xy.angle
868
+ });
869
+
870
+ // These coords arrays just store the coordinates of the points.
871
+ this.coords.push([
872
+ xy.x,
873
+ xy.y
874
+ ]);
875
+ this.coords2[dataset].push([
876
+ xy.x,
877
+ xy.y
878
+ ]);
879
+ }
880
+
881
+ // If a stacked filled charts then add the reverse path
882
+ if (dataset > 0 && properties.filled && properties.filledAccumulative) {
883
+
884
+ // Add a line completing the "circle"
885
+ path.push('L {1} {2}'.format(
886
+ this.coords2[dataset][0][0],
887
+ this.coords2[dataset][0][1]
888
+ ));
889
+
890
+ // Move to the previous dataset
891
+ path.push('M {1} {2}'.format(
892
+ this.coords2[dataset - 1][0][0],
893
+ this.coords2[dataset - 1][0][1]
894
+ ));
895
+
896
+ // Now backtrack over the previous dataset
897
+ for (var i=this.coords2[dataset - 1].length - 1; i>=0; --i) {
898
+ path.push('L {1} {2}'.format(
899
+ this.coords2[dataset - 1][i][0],
900
+ this.coords2[dataset - 1][i][1]
901
+ ));
902
+ }
903
+
904
+ this.redraw = true;
905
+
906
+ } else {
907
+ // Add the closepath
908
+ path.push('z');
909
+ }
910
+
911
+
912
+ var path = RGraph.SVG.create({
913
+ svg: this.svg,
914
+ type: 'path',
915
+ parent: this.svg.all,
916
+ attr: {
917
+ d: path.join(" "),
918
+ stroke: properties.colors[dataset],
919
+ fill: properties.filled ? properties.colors[dataset] : 'transparent',
920
+ 'fill-opacity': properties.filledOpacity,
921
+ 'stroke-width': properties.linewidth,
922
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : '',
923
+ filter: properties.shadow ? 'url(#dropShadow)' : ''
924
+ }
925
+ });
926
+
927
+ path.setAttribute('data-dataset', dataset);
928
+ }
929
+
930
+
931
+ // Redraw the chart (this only runs if necessary
932
+ this.redrawRadar();
933
+ };
934
+
935
+
936
+
937
+
938
+
939
+
940
+
941
+
942
+ //
943
+ // Redraws the chart if required
944
+ //
945
+ this.redrawRadar = function ()
946
+ {
947
+ if (this.redraw) {
948
+
949
+ this.redraw = false;
950
+
951
+ // Loop through ths coordinates
952
+ for (var dataset = 0; dataset<this.coords2.length; ++dataset) {
953
+
954
+ var path = [];
955
+
956
+ for (var i=0; i<this.coords2[dataset].length; ++i) {
957
+ if (i === 0) {
958
+ path.push('M {1} {2}'.format(
959
+ this.coords2[dataset][i][0],
960
+ this.coords2[dataset][i][1]
961
+ ));
962
+ } else {
963
+ path.push('L {1} {2}'.format(
964
+ this.coords2[dataset][i][0],
965
+ this.coords2[dataset][i][1]
966
+ ))
967
+ }
968
+ }
969
+
970
+ path.push('z')
971
+
972
+ RGraph.SVG.create({
973
+ svg: this.svg,
974
+ type: 'path',
975
+ parent: this.svg.all,
976
+ attr: {
977
+ d: path.join(" "),
978
+ stroke: properties.colors[dataset],
979
+ fill: 'transparent',
980
+ 'stroke-width': properties.linewidth
981
+ }
982
+ });
983
+ }
984
+ }
985
+ };
986
+
987
+
988
+
989
+
990
+
991
+
992
+
993
+
994
+ //
995
+ // Draw the tickmarks
996
+ //
997
+ this.drawTickmarks = function ()
998
+ {
999
+ var group = RGraph.SVG.create({
1000
+ svg: this.svg,
1001
+ parent: this.svg.all,
1002
+ type: 'g',
1003
+ attr: {
1004
+ className: 'rgraph_radar_tickmarks'
1005
+ }
1006
+ });
1007
+
1008
+ for (var i=0; i<this.coords2.length; ++i) {
1009
+ for (var j=0; j<this.coords2[i].length; ++j) {
1010
+ if (properties.tickmarksStyle === 'circle' || properties.tickmarksStyle === 'filledcircle' ) {
1011
+ var c = RGraph.SVG.create({
1012
+ svg: this.svg,
1013
+ type: 'circle',
1014
+ parent: group,
1015
+ attr: {
1016
+ cx: this.coords2[i][j][0],
1017
+ cy: this.coords2[i][j][1],
1018
+ r: properties.tickmarksSize,
1019
+ fill: properties.tickmarksStyle === 'filledcircle' ? properties.colors[i] : properties.tickmarksFill,
1020
+ stroke: properties.colors[i],
1021
+ 'stroke-width': properties.tickmarksLinewidth,
1022
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : '',
1023
+ filter: properties.shadow ? 'url(#dropShadow)' : '',
1024
+ }
1025
+ });
1026
+
1027
+ c.setAttribute('data-dataset', i);
1028
+ c.setAttribute('data-index', j);
1029
+
1030
+
1031
+ } else if (properties.tickmarksStyle === 'rect' || properties.tickmarksStyle === 'filledrect') {
1032
+
1033
+ var halfTickmarkSize = properties.tickmarksSize / 2;
1034
+ var fill = typeof properties.tickmarksFill === 'object' && properties.tickmarksFill[i] ? properties.tickmarksFill[i] : properties.tickmarksFill;
1035
+
1036
+ var s = RGraph.SVG.create({
1037
+ svg: this.svg,
1038
+ type: 'rect',
1039
+ parent: group,
1040
+ attr: {
1041
+ x: this.coords2[i][j][0] - halfTickmarkSize,
1042
+ y: this.coords2[i][j][1] - halfTickmarkSize,
1043
+ width: properties.tickmarksSize,
1044
+ height: properties.tickmarksSize,
1045
+ fill: properties.tickmarksStyle === 'filledrect' ? properties.colors[i] : fill,
1046
+ stroke: properties.colors[i],
1047
+ 'stroke-width': properties.tickmarksLinewidth,
1048
+ filter: properties.shadow ? 'url(#dropShadow)' : '',
1049
+ }
1050
+ });
1051
+
1052
+ s.setAttribute('data-dataset', i);
1053
+ s.setAttribute('data-index', j);
1054
+ }
1055
+ }
1056
+ }
1057
+ };
1058
+
1059
+
1060
+
1061
+
1062
+
1063
+
1064
+
1065
+
1066
+ //
1067
+ // Draw the labels
1068
+ //
1069
+ this.drawLabels = function ()
1070
+ {
1071
+ //
1072
+ // If the labels option is a string then turn it
1073
+ // into an array.
1074
+ //
1075
+ if (properties.labels && properties.labels.length) {
1076
+ if (typeof properties.labels === 'string') {
1077
+ properties.labels = RGraph.SVG.arrayPad({
1078
+ array: [],
1079
+ length: this.data[0].length,
1080
+ value: properties.labels
1081
+ });
1082
+ }
1083
+
1084
+ // Label substitution
1085
+ //
1086
+ for (var i=0; i<properties.labels.length; ++i) {
1087
+ properties.labels[i] = RGraph.SVG.labelSubstitution({
1088
+ object: this,
1089
+ text: properties.labels[i],
1090
+ index: i,
1091
+ value: this.data[0][i],
1092
+ decimals: properties.labelsFormattedDecimals || 0,
1093
+ unitsPre: properties.labelsFormattedUnitsPre || '',
1094
+ unitsPost: properties.labelsFormattedUnitsPost || '',
1095
+ thousand: properties.labelsFormattedThousand || ',',
1096
+ point: properties.labelsFormattedPoint || '.'
1097
+ });
1098
+ }
1099
+ }
1100
+
1101
+
1102
+
1103
+
1104
+ var angles = this.angles2,
1105
+ labels = properties.labels;
1106
+
1107
+ // Get the text configuration
1108
+ var textConf = RGraph.SVG.getTextConf({
1109
+ object: this,
1110
+ prefix: 'labels'
1111
+ });
1112
+
1113
+ for (var i=0,len=labels.length; i<len; ++i) {
1114
+
1115
+ if (!labels[i]) {
1116
+ continue;
1117
+ }
1118
+
1119
+ var endpoint = RGraph.SVG.TRIG.getRadiusEndPoint({
1120
+ angle: RGraph.SVG.TRIG.TWOPI / labels.length * i - RGraph.SVG.TRIG.HALFPI,
1121
+ r: this.radius + 20 + properties.labelsOffset
1122
+ });
1123
+
1124
+ var x = endpoint[0] + this.centerx,
1125
+ y = endpoint[1] + this.centery;
1126
+
1127
+ //
1128
+ // Horizontal alignment
1129
+
1130
+ if ((i / len) < 0.5) {
1131
+ halign = 'left';
1132
+ } else {
1133
+ halign = 'right';
1134
+ }
1135
+
1136
+ //
1137
+ // Vertical alignment
1138
+ //
1139
+ if ((i / len) < 0.25 || (i / len) > 0.75) {
1140
+ valign = 'bottom';
1141
+ } else {
1142
+ valign = 'top';
1143
+ }
1144
+
1145
+ // Specify the alignment for labels which are on the axes
1146
+ if ( (i / len) === 0 ) {halign = 'center';}
1147
+ if ( (i / len) === 0.25 ) {valign = 'center';}
1148
+ if ( (i / len) === 0.5 ) {halign = 'center';}
1149
+ if ( (i / len) === 0.75 ) {valign = 'center';}
1150
+
1151
+
1152
+ RGraph.SVG.text({
1153
+ object: this,
1154
+ svg: this.svg,
1155
+ parent: this.svg.all,
1156
+ tag: 'labels',
1157
+
1158
+ text: labels[i],
1159
+
1160
+ x: x,
1161
+ y: y,
1162
+
1163
+ halign: halign,
1164
+ valign: 'center',
1165
+
1166
+ size: textConf.size,
1167
+ color: textConf.color,
1168
+ bold: textConf.bold,
1169
+ italic: textConf.italic,
1170
+ font: textConf.font
1171
+ });
1172
+ }
1173
+
1174
+
1175
+
1176
+
1177
+
1178
+
1179
+
1180
+
1181
+
1182
+
1183
+
1184
+
1185
+ // Draw the scale if required
1186
+ if (properties.scaleVisible) {
1187
+
1188
+ // Get the text configuration
1189
+ var textConf = RGraph.SVG.getTextConf({
1190
+ object: this,
1191
+ prefix: 'scale'
1192
+ });
1193
+
1194
+ for (var i=0; i<this.scale.labels.length; ++i) {
1195
+
1196
+ var x = this.centerx;
1197
+ var y = this.centery - (this.radius / this.scale.labels.length * (i+1) );
1198
+
1199
+
1200
+ RGraph.SVG.text({
1201
+
1202
+ object: this,
1203
+ parent: this.svg.all,
1204
+ tag: 'labels.scale',
1205
+
1206
+ text: this.scale.labels[i],
1207
+
1208
+ x: x,
1209
+ y: y,
1210
+
1211
+ halign: 'center',
1212
+ valign: 'center',
1213
+
1214
+ background: 'rgba(255,255,255,0.7)',
1215
+ padding:2,
1216
+
1217
+ size: textConf.size,
1218
+ color: textConf.color,
1219
+ bold: textConf.bold,
1220
+ italic: textConf.italic,
1221
+ font: textConf.font
1222
+ });
1223
+ }
1224
+
1225
+ // Draw the zero label
1226
+ var str = RGraph.SVG.numberFormat({
1227
+ object: this,
1228
+ num: this.scale.min.toFixed(properties.scaleDecimals),
1229
+ prepend: properties.scaleUnitsPre,
1230
+ append: properties.scaleUnitsPost,
1231
+ point: properties.scalePoint,
1232
+ thousand: properties.scaleThousand,
1233
+ formatter: properties.scaleFormatter
1234
+ });
1235
+
1236
+ RGraph.SVG.text({
1237
+ object: this,
1238
+ parent: this.svg.all,
1239
+ tag: 'labels.scale',
1240
+
1241
+ text: str,
1242
+
1243
+ x: this.centerx,
1244
+ y: this.centery,
1245
+
1246
+ halign: 'center',
1247
+ valign: 'center',
1248
+
1249
+ background: 'rgba(255,255,255,0.7)',
1250
+ padding:2,
1251
+
1252
+ size: textConf.size,
1253
+ color: textConf.color,
1254
+ bold: textConf.bold,
1255
+ italic: textConf.italic,
1256
+ font: textConf.font
1257
+ });
1258
+ }
1259
+ };
1260
+
1261
+
1262
+
1263
+
1264
+
1265
+
1266
+
1267
+
1268
+ //
1269
+ // This function can be used to highlight a segment on the chart
1270
+ //
1271
+ // @param object circle The circle to highlight
1272
+ //
1273
+ this.highlight = function (circle)
1274
+ {
1275
+
1276
+ var cx = parseFloat(circle.getAttribute('cx')),
1277
+ cy = parseFloat(circle.getAttribute('cy')),
1278
+ radius = parseFloat(circle.getAttribute('r')) + 1;
1279
+
1280
+ var highlight = RGraph.SVG.create({
1281
+ svg: this.svg,
1282
+ parent: this.svg.all,
1283
+ type: 'circle',
1284
+ attr: {
1285
+ 'stroke-width': properties.highlightLinewidth,
1286
+ stroke: properties.highlightStroke,
1287
+ fill: properties.highlightFill,
1288
+ cx: cx,
1289
+ cy: cy,
1290
+ r: radius
1291
+ },
1292
+ style: {
1293
+ pointerEvents: 'none'
1294
+ }
1295
+ });
1296
+
1297
+ RGraph.SVG.REG.set('highlight', highlight);
1298
+
1299
+ //this.highlight_node = circle;
1300
+ this.highlight_node = highlight;
1301
+
1302
+ RGraph.SVG.REG.set('highlight', highlight);
1303
+ };
1304
+
1305
+
1306
+
1307
+
1308
+
1309
+
1310
+
1311
+
1312
+ // Add the hide function
1313
+ //this.hideHighlight = function ()
1314
+ //{
1315
+ // var highlight = RGraph.SVG.REG.get('highlight');
1316
+
1317
+ // if (highlight) {
1318
+ // highlight.setAttribute('fill', 'transparent');
1319
+ // highlight.setAttribute('stroke', 'transparent');
1320
+ // }
1321
+ //};
1322
+
1323
+
1324
+
1325
+
1326
+
1327
+
1328
+
1329
+
1330
+ //
1331
+ // This allows for easy specification of gradients
1332
+ //
1333
+ this.parseColors = function ()
1334
+ {
1335
+ // Save the original colors so that they can be restored when the canvas is reset
1336
+ if (!Object.keys(this.originalColors).length) {
1337
+ this.originalColors = {
1338
+ colors: RGraph.SVG.arrayClone(properties.colors),
1339
+ highlightFill: RGraph.SVG.arrayClone(properties.highlightFill)
1340
+ }
1341
+ }
1342
+
1343
+
1344
+ // colors
1345
+ var colors = properties.colors;
1346
+
1347
+ if (colors) {
1348
+ for (var i=0; i<colors.length; ++i) {
1349
+ colors[i] = RGraph.SVG.parseColorRadial({
1350
+ object: this,
1351
+ color: colors[i]
1352
+ });
1353
+ }
1354
+ }
1355
+
1356
+ // Highlight fill
1357
+ properties.highlightFill = RGraph.SVG.parseColorRadial({
1358
+ object: this,
1359
+ color: properties.highlightFill
1360
+ });
1361
+ };
1362
+
1363
+
1364
+
1365
+
1366
+
1367
+
1368
+
1369
+
1370
+ //
1371
+ // Get the maximum value
1372
+ //
1373
+ this.getMaxValue = function ()
1374
+ {
1375
+ var max = 0;
1376
+
1377
+ if (properties.filled && properties.filledAccumulative) {
1378
+ this.max = RGraph.SVG.arrayMax(this.data[this.data.length - 1]);
1379
+ } else {
1380
+ for (var dataset=0,max=0; dataset<this.data.length; ++dataset) {
1381
+ this.max = Math.max(this.max, RGraph.SVG.arrayMax(this.data[dataset]));
1382
+ }
1383
+ }
1384
+ };
1385
+
1386
+
1387
+
1388
+
1389
+
1390
+
1391
+
1392
+
1393
+ //
1394
+ // Gets the radius of a value
1395
+ //
1396
+ //@param number The value to get the radius for
1397
+ //
1398
+ this.getRadius = function (value)
1399
+ {
1400
+ return ( (value - properties.scaleMin) / (this.scale.max - properties.scaleMin) ) * this.radius;
1401
+ };
1402
+
1403
+
1404
+
1405
+
1406
+
1407
+
1408
+
1409
+
1410
+ //
1411
+ // Adds the circular hotspot that facilitate tooltips
1412
+ // (to a single point)
1413
+ //
1414
+ this.addTooltipHotspots = function ()
1415
+ {
1416
+ if (properties.tooltips && properties.tooltips.length > 0) {
1417
+
1418
+ // Make the tooltipsEvent default to click
1419
+ if (properties.tooltipsEvent !== 'mousemove') {
1420
+ properties.tooltipsEvent = 'click';
1421
+ }
1422
+
1423
+ var group = RGraph.SVG.create({
1424
+ svg: this.svg,
1425
+ type: 'g',
1426
+ parent: this.svg.all,
1427
+ attr: {
1428
+ className: 'rgraph-radar-tooltip-hotspots'
1429
+ }
1430
+ });
1431
+
1432
+ for (var dataset=0,seq=0; dataset<this.coords2.length; ++dataset) {
1433
+ for (var i=0; i<this.coords2[dataset].length; ++i) {
1434
+
1435
+ var circle = RGraph.SVG.create({
1436
+ svg: this.svg,
1437
+ type: 'circle',
1438
+ parent: group,
1439
+ attr: {
1440
+ cx: this.coords2[dataset][i][0],
1441
+ cy: this.coords2[dataset][i][1],
1442
+ r: properties.tickmarksSize,
1443
+ fill: 'transparent',
1444
+ stroke: 'transparent',
1445
+ 'stroke-width': 0,
1446
+ 'data-sequential-index': seq
1447
+ },
1448
+ style: {
1449
+ cursor: properties['tooltips'][seq] ? 'pointer' : 'default'
1450
+ }
1451
+ });
1452
+
1453
+ (function (dataset, index, seq, obj)
1454
+ {
1455
+ if (properties.tooltips[seq] || typeof properties.tooltips === 'string') {
1456
+ circle.addEventListener(properties.tooltipsEvent, function (e)
1457
+ {
1458
+ var tooltip = RGraph.SVG.REG.get('tooltip');
1459
+
1460
+ //obj.removeHighlight();
1461
+
1462
+ if (tooltip && tooltip.__sequentialIndex__ === seq) {
1463
+ return;
1464
+ }
1465
+
1466
+ // Show the tooltip
1467
+ RGraph.SVG.tooltip({
1468
+ object: obj,
1469
+ dataset: dataset,
1470
+ index: index,
1471
+ sequentialIndex: seq,
1472
+ text: typeof properties.tooltips === 'string' ? properties.tooltips : properties.tooltips[seq],
1473
+ event: e
1474
+ });
1475
+
1476
+ // Highlight the shape that has been clicked on
1477
+ obj.highlight(this);
1478
+
1479
+ }, false);
1480
+
1481
+ // Install the event listener that changes the
1482
+ // cursor if necessary
1483
+ if (properties.tooltipsEvent === 'click') {
1484
+ circle.addEventListener('mousemove', function (e)
1485
+ {
1486
+ e.target.style.cursor = 'pointer';
1487
+ }, false);
1488
+ }
1489
+ }
1490
+
1491
+ }(dataset, i, seq++, this));
1492
+ }
1493
+ }
1494
+ }
1495
+ };
1496
+
1497
+
1498
+
1499
+
1500
+
1501
+
1502
+
1503
+
1504
+ //
1505
+ // Using a function to add events makes it easier to facilitate method
1506
+ // chaining
1507
+ //
1508
+ // @param string type The type of even to add
1509
+ // @param function func
1510
+ //
1511
+ this.on = function (type, func)
1512
+ {
1513
+ if (type.substr(0,2) !== 'on') {
1514
+ type = 'on' + type;
1515
+ }
1516
+
1517
+ RGraph.SVG.addCustomEventListener(this, type, func);
1518
+
1519
+ return this;
1520
+ };
1521
+
1522
+
1523
+
1524
+
1525
+
1526
+
1527
+
1528
+
1529
+ //
1530
+ // Used in chaining. Runs a function there and then - not waiting for
1531
+ // the events to fire (eg the onbeforedraw event)
1532
+ //
1533
+ // @param function func The function to execute
1534
+ //
1535
+ this.exec = function (func)
1536
+ {
1537
+ func(this);
1538
+
1539
+ return this;
1540
+ };
1541
+
1542
+
1543
+
1544
+
1545
+
1546
+
1547
+
1548
+
1549
+ //
1550
+ // Removes the tooltip highlight from the chart
1551
+ //
1552
+ this.removeHighlight =
1553
+ this.hideHighlight = function ()
1554
+ {
1555
+ RGraph.SVG.removeHighlight();
1556
+ this.highlight_node = null;
1557
+ };
1558
+
1559
+
1560
+
1561
+
1562
+
1563
+
1564
+
1565
+
1566
+ //
1567
+ // The trace effect
1568
+ //
1569
+ // @param ... object Options to the effect
1570
+ // @param ... function A callback function to run when the effect finishes
1571
+ //
1572
+ this.trace = function ()
1573
+ {
1574
+ var opt = arguments[0] || {},
1575
+ frame = 1,
1576
+ frames = opt.frames || 120,
1577
+ obj = this
1578
+ step = 360 / frames;
1579
+
1580
+ this.isTrace = true;
1581
+
1582
+ this.draw();
1583
+
1584
+ // Create the clip area
1585
+ var clipPath = RGraph.SVG.create({
1586
+ svg: this.svg,
1587
+ parent: this.svg.defs,
1588
+ type: 'clipPath',
1589
+ attr: {
1590
+ id: 'trace-effect-clip'
1591
+ }
1592
+ });
1593
+
1594
+ clipPathArcPath = RGraph.SVG.TRIG.getArcPath2({
1595
+ cx: this.angles[0].cx,
1596
+ cy: this.angles[0].cy,
1597
+ r: this.angles[0].r * 2,
1598
+ start: 0,
1599
+ end: 0
1600
+ });
1601
+
1602
+ var clipPathArc = RGraph.SVG.create({
1603
+ svg: this.svg,
1604
+ parent: clipPath,
1605
+ type: 'path',
1606
+ attr: {
1607
+ d: clipPathArcPath
1608
+ }
1609
+ });
1610
+
1611
+
1612
+ var iterator = function ()
1613
+ {
1614
+ var width = (frame++) / frames * obj.width;
1615
+ var deg = (360 / frames) * frame++,
1616
+ rad = (RGraph.SVG.TRIG.TWOPI / 360) * deg
1617
+
1618
+ clipPathArc.setAttribute('d', RGraph.SVG.TRIG.getArcPath2({
1619
+ cx: obj.angles[0].cx,
1620
+ cy: obj.angles[0].cy,
1621
+ r: obj.angles[0].r * 2,
1622
+ start: 0,
1623
+ end: rad
1624
+ }));
1625
+
1626
+ if (frame <= frames) {
1627
+ RGraph.SVG.FX.update(iterator);
1628
+ } else if (opt.callback) {
1629
+ (opt.callback)(obj);
1630
+ }
1631
+ };
1632
+
1633
+ iterator();
1634
+
1635
+ return this;
1636
+ };
1637
+
1638
+
1639
+
1640
+
1641
+
1642
+
1643
+
1644
+
1645
+ //
1646
+ // A worker function that handles Bar chart specific tooltip substitutions
1647
+ //
1648
+ this.tooltipSubstitutions = function (opt)
1649
+ {
1650
+ var indexes = RGraph.SVG.sequentialIndexToGrouped(opt.index, this.data);
1651
+
1652
+ // Create the values array which contains each datasets value
1653
+ for (var i=0,values=[]; i<this.originalData.length; ++i) {
1654
+ values.push(this.originalData[i][indexes[1]]);
1655
+ }
1656
+
1657
+ return {
1658
+ index: indexes[1],
1659
+ dataset: indexes[0],
1660
+ sequentialIndex: opt.index,
1661
+ value: typeof this.data[indexes[0]] === 'number' ? this.data[indexes[0]] : this.data[indexes[0]][indexes[1]],
1662
+ values: values
1663
+ };
1664
+ };
1665
+
1666
+
1667
+
1668
+
1669
+
1670
+
1671
+
1672
+
1673
+ //
1674
+ // A worker function that returns the correct color/label/value
1675
+ //
1676
+ // @param object specific The indexes that are applicable
1677
+ // @param number index The appropriate index
1678
+ //
1679
+ this.tooltipsFormattedCustom = function (specific, index, colors)
1680
+ {
1681
+ var color = colors[specific.index];
1682
+ var label = ( (typeof properties.tooltipsFormattedKeyLabels === 'object' && typeof properties.tooltipsFormattedKeyLabels[specific.index] === 'string') ? properties.tooltipsFormattedKeyLabels[specific.index] : '');
1683
+
1684
+ return {
1685
+ label: label,
1686
+ color: color
1687
+ };
1688
+ };
1689
+
1690
+
1691
+
1692
+
1693
+
1694
+
1695
+
1696
+
1697
+ //
1698
+ // A worker function that returns the correct color/label/value
1699
+ //
1700
+ // @param object specific The indexes that are applicable
1701
+ // @param number index The appropriate index
1702
+ //
1703
+ this.tooltipsFormattedCustom = function (specific, index, colors)
1704
+ {
1705
+ var color = (!RGraph.SVG.isNull(properties.tooltipsFormattedKeyColors) && typeof properties.tooltipsFormattedKeyColors === 'object' && properties.tooltipsFormattedKeyColors[index])
1706
+ ? properties.tooltipsFormattedKeyColors[index]
1707
+ : '';
1708
+
1709
+ return {
1710
+ color: color
1711
+ };
1712
+ };
1713
+
1714
+
1715
+
1716
+
1717
+
1718
+
1719
+
1720
+
1721
+ //
1722
+ // This allows for static tooltip positioning
1723
+ //
1724
+ this.positionTooltipStatic = function (args)
1725
+ {
1726
+ var obj = args.object,
1727
+ e = args.event,
1728
+ tooltip = args.tooltip,
1729
+ index = args.index,
1730
+ svgXY = RGraph.SVG.getSVGXY(obj.svg),
1731
+ coords = this.coords[args.index];
1732
+
1733
+ // Position the tooltip in the X direction
1734
+ args.tooltip.style.left = (
1735
+ svgXY[0] // The X coordinate of the canvas
1736
+ + coords[0] // The X coordinate of the point on the chart
1737
+ - (tooltip.offsetWidth / 2) // Subtract half of the tooltip width
1738
+ ) + 'px';
1739
+
1740
+ args.tooltip.style.top = (
1741
+ svgXY[1] // The Y coordinate of the canvas
1742
+ + coords[1] // The Y coordinate of the point on the chart
1743
+ - tooltip.offsetHeight // The height of the tooltip
1744
+ - 15 // An arbitrary amount
1745
+ ) + 'px';
1746
+ };
1747
+
1748
+
1749
+
1750
+
1751
+
1752
+
1753
+
1754
+
1755
+ //
1756
+ // Set the options that the user has provided
1757
+ //
1758
+ for (i in conf.options) {
1759
+ if (typeof i === 'string') {
1760
+ this.set(i, conf.options[i]);
1761
+ }
1762
+ }
1763
+ };
1764
+
1765
+
1766
+
1767
+ return this;
1768
+
1769
+
1770
+
1771
+
1772
+ // End module pattern
1773
+ })(window, document);