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,66 +1,2693 @@
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.HBar=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=conf.data;this.type='hbar';this.coords=[];this.coords2=[];this.stackedBackfaces=[];this.colorsParsed=false;this.originalColors={};this.gradientCounter=1;this.propertyNameAliases={};RG.SVG.OR.add(this);this.container.style.display='inline-block';this.properties={marginLeft:100,marginRight:35,marginTop:35,marginBottom:35,marginLeftAuto:true,backgroundColor:null,backgroundImage:null,backgroundImageAspect:'none',backgroundImageStretch:true,backgroundImageOpacity:null,backgroundImageX:null,backgroundImageY:null,backgroundImageW:null,backgroundImageH:null,backgroundGrid:true,backgroundGridColor:'#ddd',backgroundGridLinewidth:1,backgroundGridHlines:true,backgroundGridHlinesCount:null,backgroundGridVlines:true,backgroundGridVlinesCount:null,backgroundGridBorder:true,backgroundGridDashed:false,backgroundGridDotted:false,backgroundGridDashArray:null,colors:['red','#0f0','#00f','#ff0','#0ff','#0f0','pink','orange','gray','black','red','#0f0','#00f','#ff0','#0ff','#0f0','pink','orange','gray','black'],colorsSequential:false,colorsStroke:'rgba(0,0,0,0)',vmargin:3,vmarginGrouped:2,vmarginTop:0,vmarginBottom:0,xaxis:true,xaxisTickmarks:true,xaxisTickmarksLength:5,xaxisColor:'black',xaxisLabels:[],xaxisLabelsOffsetx:0,xaxisLabelsOffsety:0,xaxisLabelsCount:5,xaxisScale:true,xaxisScaleUnitsPre:'',xaxisScaleUnitsPost:'',xaxisScaleStrict:false,xaxisScaleDecimals:0,xaxisScaleThousand:'.',xaxisScaleThousand:',',xaxisScaleRound:false,xaxisScaleMax:null,xaxisScaleMin:0,xaxisScaleFormatter:null,xaxisLabelsPositionEdgeTickmarksCount:null,xaxisLabelsColor:null,xaxisLabelsBold:null,xaxisLabelsItalic:null,xaxisLabelsFont:null,xaxisLabelsSize:null,yaxis:true,yaxisTickmarks:true,yaxisTickmarksLength:3,yaxisLabels:[],yaxisLabelsPosition:'section',yaxisLabelsOffsetx:0,yaxisLabelsOffsety:0,yaxisScale:false,yaxisLabelsPositionSectionTickmarksCount:null,yaxisColor:'black',yaxisLabelsFont:null,yaxisLabelsSize:null,yaxisLabelsColor:null,yaxisLabelsBold:null,yaxisLabelsItalic:null,textColor:'black',textFont:'Arial, Verdana, sans-serif',textSize:12,textBold:false,textItalic:false,labelsAbove:false,labelsAboveFont:null,labelsAboveSize:null,labelsAboveBold:null,labelsAboveItalic:null,labelsAboveColor:null,labelsAboveBackground:null,labelsAboveBackgroundPadding:0,labelsAboveUnitsPre:null,labelsAboveUnitsPost:null,labelsAbovePoint:null,labelsAboveThousand:null,labelsAboveFormatter:null,labelsAboveDecimals:null,labelsAboveOffsetx:0,labelsAboveOffsety:0,labelsAboveHalign:null,labelsAboveValign:'center',labelsAboveSpecific:null,linewidth:1,grouping:'grouped',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,titleSubtitleColor:'#aaa',titleSubtitleSize:null,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,keyLabelsColor:null,keyLabelsFont: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.coords=[];this.coords2=[];RG.SVG.createDefs(this);if(prop.marginLeftAuto){for(var i=0,len=prop.yaxisLabels.length,maxLength=0;i<len;++i){var sizes=RG.SVG.measureText({text:prop.yaxisLabels[i],bold:prop.yaxisLabelsBold||prop.textBold,size:prop.yaxisLabelsSize||prop.textSize,font:prop.yaxisLabelsFont||prop.textFont});maxLength=ma.max(maxLength,sizes[0]);}
10
- prop.marginLeft=maxLength+15-prop.yaxisLabelsOffsetx;if(prop.marginLeft<15){prop.marginLeft=15;}}
11
- this.graphWidth=this.width-prop.marginLeft-prop.marginRight;this.graphHeight=this.height-prop.marginTop-prop.marginBottom;RG.SVG.resetColorsToOriginalValues({object:this});this.parseColors();var values=[];for(var i=0,max=0;i<this.data.length;++i){if(typeof this.data[i]==='number'){values.push(this.data[i]);}else if(RG.SVG.isArray(this.data[i])&&prop.grouping==='grouped'){values.push(RG.SVG.arrayMax(this.data[i]));}else if(RG.SVG.isArray(this.data[i])&&prop.grouping==='stacked'){values.push(RG.SVG.arraySum(this.data[i]));}}
12
- var max=RG.SVG.arrayMax(values);if(typeof prop.xaxisScaleMax==='number'){max=prop.xaxisScaleMax;}
13
- if(prop.xaxisScaleMin==='mirror'||prop.xaxisScaleMin==='middle'||prop.xaxisScaleMin==='center'){var mirrorScale=true;prop.xaxisScaleMin=prop.xaxisScaleMax* -1;}
14
- this.scale=RG.SVG.getScale({object:this,numlabels:prop.xaxisLabelsCount,unitsPre:prop.xaxisScaleUnitsPre,unitsPost:prop.xaxisScaleUnitsPost,max:max,min:prop.xaxisScaleMin,point:prop.xaxisScaleThousand,round:prop.xaxisScaleRound,thousand:prop.xaxisScaleThousand,decimals:prop.xaxisScaleDecimals,strict:typeof prop.xaxisScaleMax==='number',formatter:prop.xaxisScaleFormatter});if(mirrorScale){this.scale=RG.SVG.getScale({object:this,numlabels:prop.xaxisLabelsCount,unitsPre:prop.xaxisScaleUnitsPre,unitsPost:prop.xaxisScaleUnitsPost,max:this.scale.max,min:this.scale.max* -1,point:prop.xaxisScaleThousand,round:false,thousand:prop.xaxisScaleThousand,decimals:prop.xaxisScaleDecimals,strict:typeof prop.xaxisScaleMax==='number',formatter:prop.xaxisScaleFormatter});}
15
- this.max=this.scale.max;prop.xaxisScaleMax=this.scale.max;this.min=this.scale.min;prop.xaxisScaleMin=this.scale.min;RG.SVG.drawBackground(this);this.drawBars();RG.SVG.drawXAxis(this);RG.SVG.drawYAxis(this);this.drawLabelsAbove();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?');}
16
- RG.SVG.attribution(this);var obj=this;document.body.addEventListener('mousedown',function(e)
17
- {RG.SVG.removeHighlight(obj);},false);RG.SVG.fireCustomEvent(this,'ondraw');return this;};this.drawBars=function()
18
- {if(prop.shadow){RG.SVG.setShadow({object:this,offsetx:prop.shadowOffsetx,offsety:prop.shadowOffsety,blur:prop.shadowBlur,opacity:prop.shadowOpacity,id:'dropShadow'});}
19
- for(var i=0,sequentialIndex=0;i<this.data.length;++i,++sequentialIndex){if(typeof this.data[i]==='number'){var outerSegment=(this.graphHeight-prop.vmarginTop-prop.vmarginBottom)/this.data.length,width=this.getWidth(this.data[i]),height=((this.graphHeight-prop.vmarginTop-prop.vmarginBottom)/this.data.length)-prop.vmargin-prop.vmargin,x=this.getXCoord((this.scale.min<0&&this.scale.max<0)||(this.scale.min>0&&this.scale.max>0)?this.scale.min:0)-(this.data[i]<0?width:0),y=prop.marginTop+prop.vmarginTop+prop.vmargin+(outerSegment*i);if(this.scale.min<0&&this.scale.max<0){x=this.width-prop.marginRight-width;}
20
- var rect=RG.SVG.create({svg:this.svg,parent:this.svg.all,type:'rect',attr:{stroke:prop.colorsStroke,fill:prop.colorsSequential?(prop.colors[sequentialIndex]?prop.colors[sequentialIndex]:prop.colors[prop.colors.length-1]):prop.colors[0],x:x,y:y,width:width,height:height,'stroke-width':prop.linewidth,'data-tooltip':(!RG.SVG.isNull(prop.tooltips)&&prop.tooltips.length)?prop.tooltips[i]:'','data-index':i,'data-original-width':width,'data-original-height':height,'data-sequential-index':sequentialIndex,'data-value':this.data[i],filter:prop.shadow?'url(#dropShadow)':''}});this.coords.push({object:this,element:rect,x:parseFloat(rect.getAttribute('x')),y:parseFloat(rect.getAttribute('y')),width:parseFloat(rect.getAttribute('width')),height:parseFloat(rect.getAttribute('height'))});if(!this.coords2[0]){this.coords2[0]=[];}
21
- this.coords2[0].push({object:this,element:rect,x:parseFloat(rect.getAttribute('x')),y:parseFloat(rect.getAttribute('y')),width:parseFloat(rect.getAttribute('width')),height:parseFloat(rect.getAttribute('height'))});if(!RG.SVG.isNull(prop.tooltips)&&prop.tooltips[sequentialIndex]){var obj=this;(function(idx,seq)
22
- {rect.addEventListener(prop.tooltipsEvent.replace(/^on/,''),function(e)
23
- {obj.removeHighlight();RG.SVG.tooltip({object:obj,index:idx,group:null,sequentialIndex:seq,text:prop.tooltips[seq],event:e});obj.highlight(e.target);},false);rect.addEventListener('mousemove',function(e)
24
- {e.target.style.cursor='pointer';},false);})(i,sequentialIndex);}}else if(RG.SVG.isArray(this.data[i])&&prop.grouping==='grouped'){var outerSegment=((this.graphHeight-prop.vmarginTop-prop.vmarginBottom)/this.data.length),innerSegment=outerSegment-(2*prop.vmargin);for(var j=0;j<this.data[i].length;++j,++sequentialIndex){var width=ma.abs((this.data[i][j]/(this.max-this.min))*this.graphWidth),height=((innerSegment-((this.data[i].length-1)*prop.vmarginGrouped))/this.data[i].length),y=prop.marginTop+prop.vmargin+prop.vmarginTop+(outerSegment*i)+(j*height)+(j*prop.vmarginGrouped),x=this.getXCoord(0)-(this.data[i][j]<0?width:0);if(this.scale.max<0&&this.scale.min<this.scale.max){var x1=this.getXCoord(this.data[i][j]);var x2=this.getXCoord(this.scale.max);x=x1;width=x2-x1;}else if(this.scale.min>0&&this.scale.max>this.scale.min){var x1=this.getXCoord(this.data[i][j]);var x2=this.getXCoord(this.scale.min);x=this.getXCoord(this.scale.min);width=x1-x2;}
25
- var fill;if(prop.colorsSequential){if(prop.colors[sequentialIndex]){fill=prop.colors[sequentialIndex];}}else{if(prop.colors[j]){fill=prop.colors[j];}else{fill=prop.colors[prop.colors.length-1];}}
26
- var rect=RG.SVG.create({svg:this.svg,type:'rect',parent:this.svg.all,attr:{stroke:prop['colorsStroke'],fill:fill,x:x,y:y,width:width,height:height,'stroke-width':prop.linewidth,'data-index':i,'data-original-width':width,'data-sequential-index':sequentialIndex,'data-tooltip':(!RG.SVG.isNull(prop.tooltips)&&prop.tooltips.length)?prop.tooltips[sequentialIndex]:'','data-value':this.data[i][j],filter:prop.shadow?'url(#dropShadow)':''}});this.coords.push({object:this,element:rect,x:parseFloat(rect.getAttribute('x')),y:parseFloat(rect.getAttribute('y')),width:parseFloat(rect.getAttribute('width')),height:parseFloat(rect.getAttribute('height'))});if(!this.coords2[i]){this.coords2[i]=[];}
27
- this.coords2[i].push({object:this,element:rect,x:parseFloat(rect.getAttribute('x')),y:parseFloat(rect.getAttribute('y')),width:parseFloat(rect.getAttribute('width')),height:parseFloat(rect.getAttribute('height'))});if(!RG.SVG.isNull(prop.tooltips)&&prop.tooltips[sequentialIndex]){var obj=this;(function(idx,seq)
28
- {var indexes=RG.SVG.sequentialIndexToGrouped(seq,obj.data);rect.addEventListener(prop.tooltipsEvent.replace(/^on/,''),function(e)
29
- {obj.removeHighlight();RG.SVG.tooltip({object:obj,group:idx,index:indexes[1],sequentialIndex:seq,text:prop.tooltips[seq],event:e});obj.highlight(e.target);},false);rect.addEventListener('mousemove',function(e)
30
- {e.target.style.cursor='pointer'},false);})(i,sequentialIndex);}}
31
- --sequentialIndex;}else if(RG.SVG.isArray(this.data[i])&&prop.grouping==='stacked'){var section=((this.graphHeight-prop.vmarginTop-prop.vmarginBottom)/this.data.length);var x=this.getXCoord(0);for(var j=0;j<this.data[i].length;++j,++sequentialIndex){var outerHeight=(this.graphHeight-prop.vmarginTop-prop.vmarginBottom)/this.data.length,width=ma.abs((this.data[i][j]/(this.max-this.min))*this.graphWidth),height=outerHeight-(2*prop.vmargin),y=prop.marginTop+prop.vmargin+prop.vmarginTop+(outerHeight*i);if(j===0&&prop.shadow){var fullWidth=ma.abs((RG.SVG.arraySum(this.data[i])/(this.max-this.min))*this.graphWidth);var rect=RG.SVG.create({svg:this.svg,parent:this.svg.all,type:'rect',attr:{x:x,y:y,width:fullWidth,height:height,fill:'white','stroke-width':0,'data-index':i,filter:'url(#dropShadow)'}});this.stackedBackfaces[i]=rect;}
32
- var rect=RG.SVG.create({svg:this.svg,type:'rect',parent:this.svg.all,attr:{stroke:prop['colorsStroke'],fill:prop.colorsSequential?(prop.colors[sequentialIndex]?prop.colors[sequentialIndex]:prop.colors[prop.colors.length-1]):(prop.colors[j]?prop.colors[j]:prop.colors[prop.colors.length-1]),x:x,y:y,width:width,height:height,'stroke-width':prop.linewidth,'data-original-width':width,'data-original-height':height,'data-original-x':x,'data-original-y':y,'data-index':i,'data-sequential-index':sequentialIndex,'data-tooltip':(!RG.SVG.isNull(prop.tooltips)&&prop.tooltips.length)?prop.tooltips[sequentialIndex]:'','data-value':this.data[i][j]}});this.coords.push({object:this,element:rect,x:parseFloat(rect.getAttribute('x')),y:parseFloat(rect.getAttribute('y')),width:parseFloat(rect.getAttribute('width')),height:parseFloat(rect.getAttribute('height'))});if(!this.coords2[i]){this.coords2[i]=[];}
33
- this.coords2[i].push({object:this,element:rect,x:parseFloat(rect.getAttribute('x')),y:parseFloat(rect.getAttribute('y')),width:parseFloat(rect.getAttribute('width')),height:parseFloat(rect.getAttribute('height'))});if(!RG.SVG.isNull(prop.tooltips)&&prop.tooltips[sequentialIndex]){var obj=this;(function(idx,seq)
34
- {rect.addEventListener(prop.tooltipsEvent.replace(/^on/,''),function(e)
35
- {obj.removeHighlight();var indexes=RG.SVG.sequentialIndexToGrouped(seq,obj.data);RG.SVG.tooltip({object:obj,index:indexes[1],group:idx,sequentialIndex:seq,text:prop.tooltips[seq],event:e});obj.highlight(e.target);},false);rect.addEventListener('mousemove',function(e)
36
- {e.target.style.cursor='pointer'},false);})(i,sequentialIndex);}
37
- x+=width;}
38
- --sequentialIndex;}}};this.getXCoord=function(value)
39
- {var prop=this.properties;if(value>this.scale.max){return null;}
40
- var x;if(value<this.scale.min){return null;}
41
- x=((value-this.scale.min)/(this.scale.max-this.scale.min));x*=this.graphWidth;x+=prop.marginLeft;return x;};this.getWidth=function(value)
42
- {if(this.scale.max<=0&&this.scale.min<this.scale.max){var x1=this.getXCoord(this.scale.max);var x2=this.getXCoord(value);}else if(this.scale.min>0&&this.scale.max>this.scale.min){var x1=this.getXCoord(this.scale.min);var x2=this.getXCoord(value);}else{var x1=this.getXCoord(0);var x2=this.getXCoord(value);}
43
- return ma.abs(x1-x2);};this.highlight=function(rect)
44
- {var x=rect.getAttribute('x'),y=rect.getAttribute('y'),width=rect.getAttribute('width'),height=rect.getAttribute('height');var highlight=RG.SVG.create({svg:this.svg,type:'rect',parent:this.svg.all,attr:{stroke:prop.highlightStroke,fill:prop.highlightFill,x:x,y:y,width:width,height:height,'stroke-width':prop.highlightLinewidth},style:{pointerEvents:'none'}});RG.SVG.REG.set('highlight',highlight);};this.parseColors=function()
45
- {if(!Object.keys(this.originalColors).length){this.originalColors={colors:RG.SVG.arrayClone(prop.colors),backgroundGridColor:RG.SVG.arrayClone(prop.backgroundGridColor),highlightFill:RG.SVG.arrayClone(prop.highlightFill),backgroundColor:RG.SVG.arrayClone(prop.backgroundColor)}}
46
- var colors=prop.colors;if(colors){for(var i=0;i<colors.length;++i){colors[i]=RG.SVG.parseColorLinear({object:this,color:colors[i],direction:'horizontal',start:prop.marginLeft,end:this.width-prop.marginRight});}}
47
- prop.backgroundGridColor=RG.SVG.parseColorLinear({object:this,color:prop.backgroundGridColor,direction:'horizontal',start:prop.marginLeft,end:this.width-prop.marginRight});prop.highlightFill=RG.SVG.parseColorLinear({object:this,color:prop.highlightFill,direction:'horizontal',start:prop.marginLeft,end:this.width-prop.marginRight});prop.backgroundColor=RG.SVG.parseColorLinear({object:this,color:prop.backgroundColor});};this.drawLabelsAbove=function()
48
- {if(prop.labelsAbove){var data=RG.SVG.arrayLinearize(this.data);for(var i=0;i<this.coords.length;++i){var value=data[i].toFixed(typeof prop.labelsAboveDecimals==='number'?prop.labelsAboveDecimals:prop.xaxisScaleDecimals);var indexes=RG.SVG.sequentialIndexToGrouped(i,this.data);if(RG.SVG.isArray(this.data[indexes[0]])&&prop.grouping==='stacked'){if((indexes[1]+1)===this.data[indexes[0]].length){value=RG.SVG.arraySum(this.data[indexes[0]]);value=value.toFixed(typeof prop.labelsAboveDecimals==='number'?prop.labelsAboveDecimals:prop.xaxisScaleDecimals);}else{continue;}}
49
- var str=prop.labelsAboveSpecific?prop.labelsAboveSpecific[i].toString():RG.SVG.numberFormat({object:this,num:value,prepend:typeof prop.labelsAboveUnitsPre==='string'?prop.labelsAboveUnitsPre:null,append:typeof prop.labelsAboveUnitsPost==='string'?prop.labelsAboveUnitsPost:null,point:typeof prop.labelsAbovePoint==='string'?prop.labelsAbovePoint:null,thousand:typeof prop.labelsAboveThousand==='string'?prop.labelsAboveThousand:null,formatter:typeof prop.labelsAboveFormatter==='function'?prop.labelsAboveFormatter:null});var bold=typeof prop.labelsAboveBold==='boolean'?prop.labelsAboveBold:prop.textBold,italic=typeof prop.labelsAboveItalic==='boolean'?prop.labelsAboveItalic:prop.textItalic,size=typeof prop.labelsAboveSize==='number'?prop.labelsAboveSize:prop.textSize,font=prop.labelsAboveFont||prop.textFont,halign=prop.labelsAboveHalign,valign=prop.labelsAboveValign;var dimensions=RG.SVG.measureText({text:str,bold:bold,font:font,size:size});var x=(value>=0)?(parseFloat(this.coords[i].element.getAttribute('x'))+parseFloat(this.coords[i].element.getAttribute('width'))+7+prop.labelsAboveOffsetx):parseFloat(this.coords[i].element.getAttribute('x')-7-prop.labelsAboveOffsetx),y=parseFloat(this.coords[i].element.getAttribute('y'))+parseFloat(this.coords[i].element.getAttribute('height')/2)+prop.labelsAboveOffsety,width=dimensions[0],height=dimensions[1],halign=(value>=0)?'left':'right';if(x+width>this.width&&value>0){halign='right';x=this.width-5;prop.labelsAboveBackground=prop.labelsAboveBackground||'rgba(255,255,255,0.95)';}
50
- if(typeof prop.labelsAboveHalign==='string'){halign=prop.labelsAboveHalign;}
51
- var text=RG.SVG.text({object:this,parent:this.svg.all,tag:'labels.above',text:str,x:x,y:y,halign:halign,valign:valign,font:font,size:size,bold:bold,italic:italic,color:prop.labelsAboveColor||prop.textColor,background:prop.labelsAboveBackground||null,padding:prop.labelsAboveBackgroundPadding||0});}}};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=function()
55
- {var highlight=RG.SVG.REG.get('highlight');if(highlight&&highlight.parentNode){highlight.parentNode.removeChild(highlight);}
56
- RG.SVG.REG.set('highlight',null);};this.grow=function()
57
- {var opt=arguments[0]||{},frames=opt.frames||30,frame=0,obj=this,data=[],height=null,seq=0;data=RG.SVG.arrayClone(this.data);this.draw();var iterate=function()
58
- {for(var i=0,seq=0,len=obj.coords.length;i<len;++i,++seq){var multiplier=(frame/frames)*RG.SVG.FX.getEasingMultiplier(frames,frame)*RG.SVG.FX.getEasingMultiplier(frames,frame);if(typeof data[i]==='number'){width=ma.abs(obj.getXCoord(data[i])-obj.getXCoord(0));obj.data[i]=data[i]*multiplier;width=multiplier*width;obj.coords[seq].element.setAttribute('width',width);obj.coords[seq].element.setAttribute('x',data[i]>0?obj.getXCoord(0):obj.getXCoord(0)-width);}else if(typeof data[i]==='object'){var accumulativeWidth=0;for(var j=0,len2=data[i].length;j<len2;++j,++seq){width=ma.abs(obj.getXCoord(data[i][j])-obj.getXCoord(0));width=multiplier*width;obj.data[i][j]=data[i][j]*multiplier;obj.coords[seq].element.setAttribute('width',width);obj.coords[seq].element.setAttribute('x',data[i][j]>0?(obj.getXCoord(0)+accumulativeWidth):(obj.getXCoord(0)-width-accumulativeWidth));accumulativeWidth+=(prop.grouping==='stacked'?width:0);}
59
- if(obj.stackedBackfaces[i]){obj.stackedBackfaces[i].setAttribute('width',accumulativeWidth);obj.stackedBackfaces[i].setAttribute('x',prop.marginLeft);}
60
- --seq;}}
61
- if(frame++<frames){RG.SVG.FX.update(iterate);}else if(opt.callback){(opt.callback)(obj);}};iterate();return this;};this.wave=function()
62
- {this.draw();var obj=this,opt=arguments[0]||{};opt.frames=opt.frames||60;opt.startFrames=[];opt.counters=[];var framesperbar=opt.frames/3,frame=-1,callback=opt.callback||function(){},width;for(var i=0,len=this.coords.length;i<len;i+=1){opt.startFrames[i]=((opt.frames/2)/(obj.coords.length-1))*i;opt.counters[i]=0;this.coords[i].element.setAttribute('width',0);}
63
- function iterator()
64
- {++frame;for(var i=0,len=obj.coords.length;i<len;i+=1){if(frame>opt.startFrames[i]){var originalWidth=obj.coords[i].element.getAttribute('data-original-width'),value=parseFloat(obj.coords[i].element.getAttribute('data-value'));obj.coords[i].element.setAttribute('width',width=ma.min(((frame-opt.startFrames[i])/framesperbar)*originalWidth,originalWidth));obj.coords[i].element.setAttribute('x',value>=0?obj.getXCoord(0):obj.getXCoord(0)-width);if(prop.grouping==='stacked'){var seq=obj.coords[i].element.getAttribute('data-sequential-index');var indexes=RG.SVG.sequentialIndexToGrouped(seq,obj.data);if(indexes[1]>0){obj.coords[i].element.setAttribute('x',parseInt(obj.coords[i-1].element.getAttribute('x'))+parseInt(obj.coords[i-1].element.getAttribute('width')));}}}}
65
- if(frame>=opt.frames){callback(obj);}else{RG.SVG.FX.update(iterator);}}
66
- iterator();return this;};for(i in conf.options){if(typeof i==='string'){this.set(i,conf.options[i]);}}};return this;})(window,document);
12
+
13
+ RGraph = window.RGraph || {isrgraph:true,isRGraph:true,rgraph:true};
14
+ RGraph.SVG = RGraph.SVG || {};
15
+
16
+ // Module pattern
17
+ (function (win, doc, undefined)
18
+ {
19
+ RGraph.SVG.HBar = function (conf)
20
+ {
21
+ //
22
+ // A setter that the constructor uses (at the end)
23
+ // to set all of the properties
24
+ //
25
+ // @param string name The name of the property to set
26
+ // @param string value The value to set the property to
27
+ //
28
+ this.set = function (name, value)
29
+ {
30
+ if (arguments.length === 1 && typeof name === 'object') {
31
+ for (i in arguments[0]) {
32
+ if (typeof i === 'string') {
33
+
34
+ name = ret.name;
35
+ value = ret.value;
36
+
37
+ this.set(name, value);
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
+ // Convert strings to numbers
88
+ conf.data = RGraph.SVG.stringsToNumbers(conf.data);
89
+
90
+
91
+
92
+
93
+
94
+
95
+ this.id = conf.id;
96
+ this.uid = RGraph.SVG.createUID();
97
+ this.container = document.getElementById(this.id);
98
+ this.layers = {}; // MUST be before the SVG tag is created!
99
+ this.svg = RGraph.SVG.createSVG({object: this,container: this.container});
100
+ this.isRGraph = true;
101
+ this.isrgraph = true;
102
+ this.rgraph = true;
103
+ this.width = Number(this.svg.getAttribute('width'));
104
+ this.height = Number(this.svg.getAttribute('height'));
105
+ this.data = conf.data;
106
+ this.type = 'hbar';
107
+ this.coords = [];
108
+ this.coords2 = [];
109
+ this.coordsSpline = [];
110
+ this.stackedBackfaces = [];
111
+ this.colorsParsed = false;
112
+ this.originalColors = {};
113
+ this.gradientCounter = 1;
114
+ this.isTrace = false; // Used for the vertical line trace effect
115
+ this.firstDraw = true; // After the first draw this will be false
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+ // Add this object to the ObjectRegistry
128
+ RGraph.SVG.OR.add(this);
129
+
130
+ this.container.style.display = 'inline-block';
131
+
132
+ this.properties =
133
+ {
134
+ marginLeft: 100,
135
+ marginRight: 35,
136
+ marginRightAuto: null,
137
+ marginTop: 35,
138
+ marginBottom: 35,
139
+ marginLeftAuto: true,
140
+
141
+ backgroundColor: null,
142
+ backgroundImage: null,
143
+ backgroundImageAspect: 'none',
144
+ backgroundImageStretch: true,
145
+ backgroundImageOpacity: null,
146
+ backgroundImageX: null,
147
+ backgroundImageY: null,
148
+ backgroundImageW: null,
149
+ backgroundImageH: null,
150
+ backgroundGrid: true,
151
+ backgroundGridColor: '#ddd',
152
+ backgroundGridLinewidth: 1,
153
+ backgroundGridHlines: true,
154
+ backgroundGridHlinesCount: null,
155
+ backgroundGridVlines: true,
156
+ backgroundGridVlinesCount: null,
157
+ backgroundGridBorder: true,
158
+ backgroundGridDashed: false,
159
+ backgroundGridDotted: false,
160
+ backgroundGridDashArray: null,
161
+
162
+ // 20 colors. If you need more you need to set the colors property
163
+ colors: [
164
+ 'red', '#0f0', '#00f', '#ff0', '#0ff', '#0f0','pink','orange','gray','black',
165
+ 'red', '#0f0', '#00f', '#ff0', '#0ff', '#0f0','pink','orange','gray','black'
166
+ ],
167
+ colorsSequential: false,
168
+ colorsStroke: 'rgba(0,0,0,0)',
169
+
170
+ marginInner: 3,
171
+ marginInnerGrouped: 2,
172
+ marginInnerTop: 0,
173
+ marginInnerBottom: 0,
174
+
175
+ xaxis: true,
176
+ xaxisTickmarks: true,
177
+ xaxisTickmarksLength: 5,
178
+ xaxisColor: 'black',
179
+ xaxisLabels: [],
180
+ xaxisLabelsOffsetx: 0,
181
+ xaxisLabelsOffsety: 0,
182
+ xaxisLabelsCount: 5,
183
+ xaxisScale: true,
184
+ xaxisScaleUnitsPre: '',
185
+ xaxisScaleUnitsPost: '',
186
+ xaxisScaleStrict: false,
187
+ xaxisScaleDecimals: 0,
188
+ xaxisScaleThousand: '.',
189
+ xaxisScaleThousand: ',',
190
+ xaxisScaleRound: false,
191
+ xaxisScaleMax: null,
192
+ xaxisScaleMin: 0,
193
+ xaxisScaleFormatter: null,
194
+ xaxisLabelsPositionEdgeTickmarksCount: null,
195
+ xaxisLabelsColor: null,
196
+ xaxisLabelsBold: null,
197
+ xaxisLabelsItalic: null,
198
+ xaxisLabelsFont: null,
199
+ xaxisLabelsSize: null,
200
+ xaxisTitle: '',
201
+ xaxisTitleBold: null,
202
+ xaxisTitleSize: null,
203
+ xaxisTitleFont: null,
204
+ xaxisTitleColor: null,
205
+ xaxisTitleItalic: null,
206
+ xaxisTitleOffsetx: 0,
207
+ xaxisTitleOffsety: 0,
208
+ xaxisTitleX: null,
209
+ xaxisTitleY: null,
210
+ xaxisTitleHalign: null,
211
+ xaxisTitleValign: null,
212
+
213
+ yaxis: true,
214
+ yaxisTickmarks: true,
215
+ yaxisTickmarksLength: 3,
216
+ yaxisTickmarksCount: 5,
217
+ yaxisLabels: [],
218
+ yaxisLabelsPosition: 'section',
219
+ yaxisLabelsOffsetx: 0,
220
+ yaxisLabelsOffsety: 0,
221
+ yaxisScale: false,
222
+ yaxisLabelsPositionSectionTickmarksCount: null,
223
+ yaxisColor: 'black',
224
+ yaxisLabelsFont: null,
225
+ yaxisLabelsSize: null,
226
+ yaxisLabelsColor: null,
227
+ yaxisLabelsBold: null,
228
+ yaxisLabelsItalic: null,
229
+ yaxisPosition: 'left',
230
+ yaxisLabelsFormattedDecimals: 0,
231
+ yaxisLabelsFormattedUnitsPre: '',
232
+ yaxisLabelsFormattedUnitsPost: '',
233
+ yaxisLabelsFormattedThousand: ',',
234
+ yaxisLabelsFormattedPoint: '.',
235
+ yaxisTitle: '',
236
+ yaxisTitleBold: null,
237
+ yaxisTitleSize: null,
238
+ yaxisTitleFont: null,
239
+ yaxisTitleColor: null,
240
+ yaxisTitleItalic: null,
241
+ yaxisTitleOffsetx: 0,
242
+ yaxisTitleOffsety: 0,
243
+ yaxisTitleX: null,
244
+ yaxisTitleY: null,
245
+ yaxisTitleHalign: null,
246
+ yaxisTitleValign: null,
247
+
248
+ textColor: 'black',
249
+ textFont: 'Arial, Verdana, sans-serif',
250
+ textSize: 12,
251
+ textBold: false,
252
+ textItalic: false,
253
+ text: null,
254
+
255
+ labelsAbove: false,
256
+ labelsAboveFont: null,
257
+ labelsAboveSize: null,
258
+ labelsAboveBold: null,
259
+ labelsAboveItalic: null,
260
+ labelsAboveColor: null,
261
+ labelsAboveBackground: null,
262
+ labelsAboveBackgroundPadding: 0,
263
+ labelsAboveUnitsPre: null,
264
+ labelsAboveUnitsPost: null,
265
+ labelsAbovePoint: null,
266
+ labelsAboveThousand: null,
267
+ labelsAboveFormatter: null,
268
+ labelsAboveDecimals: null,
269
+ labelsAboveOffsetx: 0,
270
+ labelsAboveOffsety: 0,
271
+ labelsAboveHalign: null,
272
+ labelsAboveValign: 'center',
273
+ labelsAboveSpecific: null,
274
+
275
+ labelsInbar: false,
276
+ labelsInbarHalign: 'center',
277
+ labelsInbarValign: 'center',
278
+ labelsInbarFont: null,
279
+ labelsInbarSize: null,
280
+ labelsInbarBold: null,
281
+ labelsInbarItalic: null,
282
+ labelsInbarColor: null,
283
+ labelsInbarBackground: null,
284
+ labelsInbarBackgroundPadding: 0,
285
+ labelsInbarUnitsPre: null,
286
+ labelsInbarUnitsPost: null,
287
+ labelsInbarPoint: null,
288
+ labelsInbarThousand: null,
289
+ labelsInbarFormatter: null,
290
+ labelsInbarDecimals: null,
291
+ labelsInbarOffsetx: 0,
292
+ labelsInbarOffsety: 0,
293
+ labelsInbarSpecific: null,
294
+
295
+ linewidth: 1,
296
+ grouping: 'grouped',
297
+
298
+ tooltips: null,
299
+ tooltipsOverride: null,
300
+ tooltipsEffect: 'fade',
301
+ tooltipsCssClass: 'RGraph_tooltip',
302
+ tooltipsCss: null,
303
+ tooltipsEvent: 'click',
304
+ tooltipsFormattedThousand: ',',
305
+ tooltipsFormattedPoint: '.',
306
+ tooltipsFormattedDecimals: 0,
307
+ tooltipsFormattedUnitsPre: '',
308
+ tooltipsFormattedUnitsPost: '',
309
+ tooltipsFormattedKeyColors: null,
310
+ tooltipsFormattedKeyColorsShape: 'square',
311
+ tooltipsFormattedKeyLabels: [],
312
+ tooltipsFormattedTableHeaders: null,
313
+ tooltipsFormattedTableData: null,
314
+ tooltipsPointer: true,
315
+ tooltipsPointerOffsetx: 0,
316
+ tooltipsPointerOffsety: 0,
317
+ tooltipsPositionStatic: true,
318
+
319
+ highlightStroke: 'rgba(0,0,0,0)',
320
+ highlightFill: 'rgba(255,255,255,0.7)',
321
+ highlightLinewidth: 1,
322
+
323
+ title: '',
324
+ titleX: null,
325
+ titleY: null,
326
+ titleHalign: 'center',
327
+ titleValign: null,
328
+ titleSize: null,
329
+ titleColor: null,
330
+ titleFont: null,
331
+ titleBold: null,
332
+ titleItalic: null,
333
+
334
+ titleSubtitle: null,
335
+ titleSubtitleColor: '#aaa',
336
+ titleSubtitleSize: null,
337
+ titleSubtitleFont: null,
338
+ titleSubtitleBold: null,
339
+ titleSubtitleItalic: null,
340
+
341
+ shadow: false,
342
+ shadowOffsetx: 2,
343
+ shadowOffsety: 2,
344
+ shadowBlur: 2,
345
+ shadowColor: 'rgba(0,0,0,0.25)',
346
+
347
+
348
+
349
+ key: null,
350
+ keyColors: null,
351
+ keyOffsetx: 0,
352
+ keyOffsety: 0,
353
+ keyLabelsOffsetx: 0,
354
+ keyLabelsOffsety: -1,
355
+ keyLabelsSize: null,
356
+ keyLabelsBold: null,
357
+ keyLabelsItalic: null,
358
+ keyLabelsColor: null,
359
+ keyLabelsFont: null,
360
+
361
+ line: false,
362
+ lineLinejoin: 'round',
363
+ lineLinecap: 'round',
364
+ lineLinewidth: 2,
365
+ lineTickmarksLinewidth: 2,
366
+ lineTickmarksStyle: null,
367
+ lineTickmarksSize: 5,
368
+ lineColor: 'black',
369
+ lineShadow: true,
370
+ lineShadowColor: '#666',
371
+ lineShadowBlur: 2,
372
+ lineShadowOffsetx: 2,
373
+ lineShadowOffsety: 2,
374
+ lineSpline: false,
375
+ lineTickmarksDrawNonNull: false
376
+ };
377
+
378
+
379
+
380
+
381
+ //
382
+ // Copy the global object properties to this instance
383
+ //
384
+ RGraph.SVG.getGlobals(this);
385
+
386
+
387
+
388
+
389
+
390
+ //
391
+ // "Decorate" the object with the generic effects if the effects library has been included
392
+ //
393
+ if (RGraph.SVG.FX && typeof RGraph.SVG.FX.decorate === 'function') {
394
+ RGraph.SVG.FX.decorate(this);
395
+ }
396
+
397
+
398
+
399
+
400
+
401
+ // Add the responsive function to the object
402
+ this.responsive = RGraph.SVG.responsive;
403
+
404
+
405
+
406
+
407
+
408
+ var properties = this.properties;
409
+
410
+
411
+
412
+
413
+
414
+
415
+
416
+
417
+ //
418
+ // The draw method draws the Bar chart
419
+ //
420
+ this.draw = function ()
421
+ {
422
+ // Fire the beforedraw event
423
+ RGraph.SVG.fireCustomEvent(this, 'onbeforedraw');
424
+
425
+
426
+
427
+
428
+ //
429
+ // Do the yaxis label substitution. This has to be called
430
+ // before the left (or right) margin size is calculated.
431
+ //
432
+ this.yaxisLabelSubstitution();
433
+
434
+
435
+
436
+
437
+ // Should the first thing that's done inthe.draw() function
438
+ // except for the onbeforedraw event
439
+ this.width = Number(this.svg.getAttribute('width'));
440
+ this.height = Number(this.svg.getAttribute('height'));
441
+
442
+ this.coords = [];
443
+ this.coords2 = [];
444
+
445
+
446
+
447
+ // Create the defs tag if necessary
448
+ RGraph.SVG.createDefs(this);
449
+
450
+
451
+
452
+ //
453
+ // Handle the marginLeft autosizing
454
+ //
455
+ if (properties.marginLeftAuto) {
456
+
457
+ var textConf = RGraph.SVG.getTextConf({
458
+ object: this,
459
+ prefix: 'yaxisLabels'
460
+ });
461
+
462
+ for (var i=0,len=properties.yaxisLabels.length,maxLength=0; i<len; ++i) {
463
+ var sizes = RGraph.SVG.measureText({
464
+ text: properties.yaxisLabels[i],
465
+ bold: textConf.bold,
466
+ size: textConf.size,
467
+ font: textConf.font,
468
+ italic: textConf.italic
469
+ });
470
+
471
+ maxLength = Math.max(maxLength, sizes[0]);
472
+ }
473
+
474
+ //
475
+ // If there's a Y axis title specified then account for that
476
+ //
477
+ if (properties.yaxisTitle) {
478
+ var textConf_title = RGraph.SVG.getTextConf({
479
+ object: this,
480
+ prefix: 'yaxisTitle'
481
+ });
482
+
483
+ var yaxisTitleSize = RGraph.SVG.measureText({
484
+ text: properties.yaxisTitle,
485
+ bold: textConf_title.bold,
486
+ size: textConf_title.size,
487
+ font: textConf_title.font,
488
+ font: textConf_title.italic
489
+ });
490
+
491
+ maxLength = maxLength + yaxisTitleSize[1];
492
+ }
493
+
494
+ properties.marginLeft = maxLength + 15;
495
+
496
+ // Minimum left margin of 15
497
+ if (properties.marginLeft < 15) {
498
+ properties.marginLeft = 15;
499
+ }
500
+ }
501
+
502
+ // Handle margin right autosizing for when the
503
+ // yaxisPosition is set to ight
504
+ if (properties.yaxisPosition === 'right' && properties.marginRightAuto !== false) {
505
+ for (var i=0,len=properties.yaxisLabels.length,maxLength=0; i<len; ++i) {
506
+ var sizes = RGraph.SVG.measureText({
507
+ text: properties.yaxisLabels[i],
508
+ bold: properties.yaxisLabelsBold || properties.textBold,
509
+ size: properties.yaxisLabelsSize || properties.textSize,
510
+ font: properties.yaxisLabelsFont || properties.textFont
511
+ });
512
+
513
+ maxLength = Math.max(maxLength, sizes[0]);
514
+ }
515
+
516
+ properties.marginRight = maxLength + 15;
517
+
518
+ // Minimum right margin of 15
519
+ if (properties.marginRight < 15) {
520
+ properties.marginRight = 15;
521
+ }
522
+ }
523
+
524
+
525
+
526
+
527
+ this.graphWidth = this.width - properties.marginLeft - properties.marginRight;
528
+ this.graphHeight = this.height - properties.marginTop - properties.marginBottom;
529
+
530
+
531
+
532
+ // Parse the colors for gradients
533
+ RGraph.SVG.resetColorsToOriginalValues({object:this});
534
+ this.parseColors();
535
+
536
+
537
+
538
+ // Go through the data and work out the maximum value
539
+ var values = [];
540
+
541
+ for (var i=0,max=0; i<this.data.length; ++i) {
542
+ if (typeof this.data[i] === 'number') {
543
+ values.push(this.data[i]);
544
+
545
+ } else if (RGraph.SVG.isArray(this.data[i]) && properties.grouping === 'grouped') {
546
+ values.push(RGraph.SVG.arrayMax(this.data[i]));
547
+
548
+ } else if (RGraph.SVG.isArray(this.data[i]) && properties.grouping === 'stacked') {
549
+ values.push(RGraph.SVG.arraySum(this.data[i]));
550
+ }
551
+ }
552
+ var max = RGraph.SVG.arrayMax(values);
553
+
554
+ // A custom, user-specified maximum value
555
+ if (typeof properties.xaxisScaleMax === 'number') {
556
+ max = properties.xaxisScaleMax;
557
+ }
558
+
559
+ // Set the ymin to zero if it's set to mirror
560
+ if (properties.xaxisScaleMin === 'mirror' || properties.xaxisScaleMin === 'middle' || properties.xaxisScaleMin === 'center') {
561
+ this.mirrorScale = true;
562
+ properties.xaxisScaleMin = properties.xaxisScaleMax * -1;
563
+ }
564
+
565
+
566
+ //
567
+ // Generate an appropiate scale
568
+ //
569
+ this.scale = RGraph.SVG.getScale({
570
+ object: this,
571
+ numlabels: properties.xaxisLabelsCount,
572
+ unitsPre: properties.xaxisScaleUnitsPre,
573
+ unitsPost: properties.xaxisScaleUnitsPost,
574
+ max: max,
575
+ min: properties.xaxisScaleMin,
576
+ point: properties.xaxisScalePoint,
577
+ round: properties.xaxisScaleRound,
578
+ thousand: properties.xaxisScaleThousand,
579
+ decimals: properties.xaxisScaleDecimals,
580
+ strict: typeof properties.xaxisScaleMax === 'number',
581
+ formatter: properties.xaxisScaleFormatter
582
+ });
583
+
584
+
585
+
586
+ //
587
+ // Get the scale a second time if the xmin should be mirored
588
+ //
589
+ // Set the xmin to zero if it's set mirror
590
+ if (this.mirrorScale) {
591
+ this.scale = RGraph.SVG.getScale({
592
+ object: this,
593
+ numlabels: properties.xaxisLabelsCount,
594
+ unitsPre: properties.xaxisScaleUnitsPre,
595
+ unitsPost: properties.xaxisScaleUnitsPost,
596
+ max: this.scale.max,
597
+ min: this.scale.max * -1,
598
+ point: properties.xaxisScaleThousand,
599
+ round: false,
600
+ thousand: properties.xaxisScaleThousand,
601
+ decimals: properties.xaxisScaleDecimals,
602
+ strict: typeof properties.xaxisScaleMax === 'number',
603
+ formatter: properties.xaxisScaleFormatter
604
+ });
605
+ }
606
+
607
+ // Now the scale has been generated adopt its max value
608
+ this.max = this.scale.max;
609
+ properties.xaxisScaleMax = this.scale.max;
610
+
611
+ this.min = this.scale.min;
612
+ properties.xaxisScaleMin = this.scale.min;
613
+
614
+
615
+
616
+
617
+ // Draw the background first
618
+ RGraph.SVG.drawBackground(this);
619
+
620
+ // Draw the bars
621
+ this.drawBars();
622
+
623
+
624
+ // Draw the axes over the bars
625
+ RGraph.SVG.drawXAxis(this);
626
+ RGraph.SVG.drawYAxis(this);
627
+
628
+
629
+ // Draw the labelsAbove
630
+ this.drawLabelsAbove();
631
+
632
+
633
+ // Draw the labelsInbar
634
+ this.drawLabelsInbar();
635
+
636
+
637
+ // Draw the verical line
638
+ if (this.properties.line) {
639
+ this.drawLine();
640
+ }
641
+
642
+
643
+
644
+
645
+
646
+
647
+ // Draw the key
648
+ if (typeof properties.key !== null && RGraph.SVG.drawKey) {
649
+ RGraph.SVG.drawKey(this);
650
+ } else if (!RGraph.SVG.isNull(properties.key)) {
651
+ alert('The drawKey() function does not exist - have you forgotten to include the key library?');
652
+ }
653
+
654
+
655
+
656
+
657
+
658
+
659
+
660
+
661
+
662
+
663
+ // Add the event listener that clears the highlight rect if
664
+ // there is any. Must be MOUSEDOWN (ie before the click event)
665
+ var obj = this;
666
+ document.body.addEventListener('mousedown', function (e)
667
+ {
668
+ RGraph.SVG.removeHighlight(obj);
669
+
670
+ }, false);
671
+
672
+
673
+
674
+
675
+
676
+
677
+
678
+
679
+ //
680
+ // Allow the addition of custom text via the
681
+ // text: property.
682
+ //
683
+ RGraph.SVG.addCustomText(this);
684
+
685
+
686
+
687
+
688
+
689
+
690
+
691
+
692
+
693
+
694
+
695
+
696
+
697
+ //
698
+ // Fire the onfirstdraw event
699
+ //
700
+ if (this.firstDraw) {
701
+ this.firstDraw = false;
702
+ RGraph.SVG.fireCustomEvent(this, 'onfirstdraw');
703
+ }
704
+
705
+
706
+
707
+
708
+
709
+
710
+ // Fire the draw event
711
+ RGraph.SVG.fireCustomEvent(this, 'ondraw');
712
+
713
+
714
+
715
+
716
+
717
+
718
+
719
+ //
720
+ // Install any inline responsive configuration. This
721
+ // should be last in the draw function - even after
722
+ // the draw events.
723
+ //
724
+ RGraph.SVG.installInlineResponsive(this);
725
+
726
+
727
+
728
+
729
+
730
+
731
+
732
+
733
+
734
+
735
+
736
+
737
+ return this;
738
+ };
739
+
740
+
741
+
742
+
743
+
744
+
745
+
746
+
747
+ //
748
+ // New create() shortcut function
749
+ // For example:
750
+ // this.create('rect,x:0,y:0,width:100,height:100'[,parent]);
751
+ //
752
+ // @param str string The tag definition to parse and create
753
+ // @param object The (optional) parent element
754
+ // @return object The new tag
755
+ //
756
+ this.create = function (str)
757
+ {
758
+ var def = RGraph.SVG.create.parseStr(this, str);
759
+ def.svg = this.svg;
760
+
761
+ // By default the parent is the SVG tag - but if
762
+ // requested then change it to the tag that has
763
+ // been given
764
+ if (arguments[1]) {
765
+ def.parent = arguments[1];
766
+ }
767
+
768
+ return RGraph.SVG.create(def);
769
+ };
770
+
771
+
772
+
773
+
774
+
775
+
776
+
777
+
778
+ //
779
+ // Do the label substitution. This is called from the top of the
780
+ // draw function
781
+ //
782
+ this.yaxisLabelSubstitution = function ()
783
+ {
784
+ if (properties.yaxisLabels && properties.yaxisLabels.length) {
785
+ //
786
+ // If the yaxisLabels option is a string then turn it
787
+ // into an array.
788
+ //
789
+ if (typeof properties.yaxisLabels === 'string') {
790
+ properties.yaxisLabels = RGraph.SVG.arrayPad({
791
+ array: [],
792
+ length: this.data.length,
793
+ value: properties.yaxisLabels
794
+ });
795
+ }
796
+
797
+ //
798
+ // Label substitution
799
+ //
800
+ for (var i=0; i<properties.yaxisLabels.length; ++i) {
801
+ properties.yaxisLabels[i] = RGraph.SVG.labelSubstitution({
802
+ object: this,
803
+ text: properties.yaxisLabels[i],
804
+ index: i,
805
+ value: this.data[i],
806
+ decimals: properties.yaxisLabelsFormattedDecimals || 0,
807
+ unitsPre: properties.yaxisLabelsFormattedUnitsPre || '',
808
+ unitsPost: properties.yaxisLabelsFormattedUnitsPost || '',
809
+ thousand: properties.yaxisLabelsFormattedThousand || ',',
810
+ point: properties.yaxisLabelsFormattedPoint || '.'
811
+ });
812
+ }
813
+ }
814
+ };
815
+
816
+
817
+
818
+
819
+
820
+
821
+
822
+
823
+ //
824
+ // Draws the bars
825
+ //
826
+ this.drawBars = function ()
827
+ {
828
+ if (properties.shadow) {
829
+ RGraph.SVG.setShadow({
830
+ object: this,
831
+ offsetx: properties.shadowOffsetx,
832
+ offsety: properties.shadowOffsety,
833
+ blur: properties.shadowBlur,
834
+ color: properties.shadowColor,
835
+ id: 'dropShadow'
836
+ });
837
+ }
838
+
839
+ // Go through the bars
840
+ for (var i=0,sequentialIndex=0; i<this.data.length; ++i,++sequentialIndex) {
841
+
842
+ // Put place holders in the coords arrays
843
+ // for NULL VALUES
844
+ if (RGraph.SVG.isNull(this.data[i])) {
845
+ this.coords.push([]);
846
+ this.coords2.push([]);
847
+ }
848
+
849
+ //
850
+ // NORMAL bars
851
+ //
852
+ if (typeof this.data[i] === 'number') {
853
+
854
+ var outerSegment = (this.graphHeight - properties.marginInnerTop - properties.marginInnerBottom) / this.data.length,
855
+ width = this.getWidth(this.data[i]),
856
+ height = ( (this.graphHeight - properties.marginInnerTop - properties.marginInnerBottom) / this.data.length) - properties.marginInner - properties.marginInner,
857
+ x = this.getXCoord(
858
+ (this.scale.min < 0 && this.scale.max < 0) || (this.scale.min > 0 && this.scale.max > 0) ? this.scale.min : 0
859
+ ) - (this.data[i] < 0 ? width : 0),
860
+ y = properties.marginTop + properties.marginInnerTop + properties.marginInner + (outerSegment * i);
861
+
862
+ // Allow for the Y axis to be positioned on the right hand side
863
+ if (properties.yaxisPosition === 'right' && this.scale.min >= 0) {
864
+ x = this.getXCoord(this.data[i]);
865
+ }
866
+
867
+ if (properties.yaxisPosition === 'right' && this.scale.min < 0) {
868
+ x = this.getXCoord(0);
869
+ }
870
+
871
+ // If theres a min set but both the min and max are below
872
+ // zero the bars should be aligned to the right hand
873
+ // side
874
+ if (this.scale.min < 0 && this.scale.max < 0) {
875
+ x = this.width - properties.marginRight - width;
876
+ }
877
+
878
+ // Adjust for a negative value
879
+ if (this.mirrorScale && properties.yaxisPosition === 'right') {
880
+ if (this.data[i] > 0) {
881
+ x = this.getXCoord(0) - width;
882
+ } else {
883
+ x = this.getXCoord(0);
884
+ }
885
+ }
886
+
887
+ // If the X axis is right, move the bar left
888
+ if (this.data[i] > 0 && properties.yaxisPosition === 'right') {
889
+ x = this.getXCoord(0) - width;
890
+ }
891
+
892
+ var rect = RGraph.SVG.create({
893
+ svg: this.svg,
894
+ parent: this.svg.all,
895
+ type: 'rect',
896
+ attr: {
897
+ stroke: properties.colorsStroke,
898
+ fill: properties.colorsSequential ? (properties.colors[sequentialIndex] ? properties.colors[sequentialIndex] : properties.colors[properties.colors.length - 1]) : properties.colors[0],
899
+ x: x,
900
+ y: y,
901
+ width: width,
902
+ height: height,
903
+ 'stroke-width': properties.linewidth,
904
+ 'data-tooltip': (!RGraph.SVG.isNull(properties.tooltips) && properties.tooltips.length) ? properties.tooltips[i] : '',
905
+ 'data-index': i,
906
+ 'data-original-x': x,
907
+ 'data-original-y': y,
908
+ 'data-original-width': width,
909
+ 'data-original-height': height,
910
+ 'data-sequential-index': sequentialIndex,
911
+ 'data-value': this.data[i],
912
+ filter: properties.shadow ? 'url(#dropShadow)' : ''
913
+ }
914
+ });
915
+
916
+ this.coords.push({
917
+ object: this,
918
+ element: rect,
919
+ x: parseFloat(rect.getAttribute('x')),
920
+ y: parseFloat(rect.getAttribute('y')),
921
+ width: parseFloat(rect.getAttribute('width')),
922
+ height: parseFloat(rect.getAttribute('height'))
923
+ });
924
+
925
+ if (!this.coords2[i]) {
926
+ this.coords2[i] = [];
927
+ }
928
+
929
+ this.coords2[i].push({
930
+ object: this,
931
+ element: rect,
932
+ x: parseFloat(rect.getAttribute('x')),
933
+ y: parseFloat(rect.getAttribute('y')),
934
+ width: parseFloat(rect.getAttribute('width')),
935
+ height: parseFloat(rect.getAttribute('height'))
936
+ });
937
+
938
+
939
+
940
+
941
+
942
+ // Add toooltips if necessary
943
+ if (!RGraph.SVG.isNull(properties.tooltips) && (properties.tooltips[sequentialIndex] || typeof properties.tooltips === 'string')) {
944
+
945
+ var obj = this;
946
+
947
+ //
948
+ // Add tooltip event listeners
949
+ //
950
+ (function (idx, seq)
951
+ {
952
+ rect.addEventListener(properties.tooltipsEvent.replace(/^on/, ''), function (e)
953
+ {
954
+ obj.removeHighlight();
955
+
956
+ // Show the tooltip
957
+ RGraph.SVG.tooltip({
958
+ object: obj,
959
+ index: idx,
960
+ group: null,
961
+ sequentialIndex: seq,
962
+ text: typeof properties.tooltips === 'string' ? properties.tooltips : properties.tooltips[seq],
963
+ event: e
964
+ });
965
+
966
+ // Highlight the rect that has been clicked on
967
+ obj.highlight(e.target);
968
+ }, false);
969
+
970
+ rect.addEventListener('mousemove', function (e)
971
+ {
972
+ e.target.style.cursor = 'pointer';
973
+ }, false);
974
+ })(i, sequentialIndex);
975
+ }
976
+
977
+
978
+
979
+
980
+ //
981
+ // GROUPED charts
982
+ //
983
+ } else if (RGraph.SVG.isArray(this.data[i]) && properties.grouping === 'grouped') {
984
+
985
+ var outerSegment = ( (this.graphHeight - properties.marginInnerTop - properties.marginInnerBottom) / this.data.length),
986
+ innerSegment = outerSegment - (2 * properties.marginInner);
987
+
988
+ // Loop through the group
989
+ for (var j=0; j<this.data[i].length; ++j,++sequentialIndex) {
990
+
991
+ var width = Math.abs((this.data[i][j] / (this.max - this.min)) * this.graphWidth),
992
+ height = ( (innerSegment - ((this.data[i].length - 1) * properties.marginInnerGrouped)) / this.data[i].length),
993
+ y = properties.marginTop + properties.marginInner + properties.marginInnerTop + (outerSegment * i) + (j * height) + (j * properties.marginInnerGrouped),
994
+ x = this.getXCoord(0) - (this.data[i][j] < 0 ? width : 0);
995
+
996
+ // Work out some coordinates for the width and X coords ///////////////////////
997
+ if (this.scale.max < 0 && this.scale.min < this.scale.max) {
998
+ var x1 = this.getXCoord(this.data[i][j]);
999
+ var x2 = this.getXCoord(this.scale.max);
1000
+ x = x1;
1001
+ width = x2 - x1;
1002
+
1003
+ } else if (this.scale.min > 0 && this.scale.max > this.scale.min) {
1004
+ var x1 = this.getXCoord(this.data[i][j]);
1005
+ var x2 = this.getXCoord(this.scale.min);
1006
+ x = this.getXCoord(this.scale.min);
1007
+ width = x1 - x2;
1008
+
1009
+ }
1010
+ //////////////////////////////////////////////////////////////////////////////
1011
+
1012
+ // Allow for the Y axis to be positioned on the right hand side
1013
+ if (properties.yaxisPosition === 'right' && this.scale.min === 0) {
1014
+ x = this.getXCoord(this.data[i][j]);
1015
+ }
1016
+
1017
+ // Allow for the Y axis to be positioned on the right hand side
1018
+ // with a scale of (for example) -5 -> 20
1019
+ if ( properties.yaxisPosition === 'right'
1020
+ && this.scale.min < 0
1021
+ && this.scale.max >= 0) {
1022
+
1023
+ if (this.data[i][j] < 0) {
1024
+ x = this.getXCoord(0);
1025
+ } else {
1026
+ x = this.getXCoord(this.data[i][j]);
1027
+ }
1028
+ }
1029
+
1030
+ // Fixes an odd bug
1031
+ //if (this.mirrorScale && properties.yaxisPosition === 'right') {
1032
+ // if (this.data[i][j] > 0) {
1033
+ // x -= width;
1034
+ // } else {
1035
+ // x += width;
1036
+ // }
1037
+ //}
1038
+
1039
+
1040
+
1041
+
1042
+
1043
+
1044
+
1045
+
1046
+ //
1047
+ // Determine the fill color
1048
+ //
1049
+ var fill;
1050
+
1051
+ if (properties.colorsSequential) {
1052
+ if (properties.colors[sequentialIndex]) {
1053
+ fill = properties.colors[sequentialIndex];
1054
+ }
1055
+ } else {
1056
+ if (properties.colors[j]) {
1057
+ fill = properties.colors[j];
1058
+ } else {
1059
+ fill = properties.colors[properties.colors.length - 1];
1060
+ }
1061
+ }
1062
+
1063
+
1064
+
1065
+
1066
+ var rect = RGraph.SVG.create({
1067
+ svg: this.svg,
1068
+ type: 'rect',
1069
+ parent: this.svg.all,
1070
+ attr: {
1071
+ stroke: properties['colorsStroke'],
1072
+ fill: fill,
1073
+ x: x,
1074
+ y: y,
1075
+ width: width,
1076
+ height: height,
1077
+ 'stroke-width': properties.linewidth,
1078
+ 'data-index': i,
1079
+ 'data-original-x': x,
1080
+ 'data-original-y': y,
1081
+ 'data-original-width': width,
1082
+ 'data-original-height': height,
1083
+ 'data-sequential-index': sequentialIndex,
1084
+ 'data-tooltip': (!RGraph.SVG.isNull(properties.tooltips) && properties.tooltips.length) ? properties.tooltips[sequentialIndex] : '',
1085
+ 'data-value': this.data[i][j],
1086
+ filter: properties.shadow ? 'url(#dropShadow)' : ''
1087
+ }
1088
+ });
1089
+
1090
+ this.coords.push({
1091
+ object: this,
1092
+ element: rect,
1093
+ x: parseFloat(rect.getAttribute('x')),
1094
+ y: parseFloat(rect.getAttribute('y')),
1095
+ width: parseFloat(rect.getAttribute('width')),
1096
+ height: parseFloat(rect.getAttribute('height'))
1097
+ });
1098
+
1099
+ if (!this.coords2[i]) {
1100
+ this.coords2[i] = [];
1101
+ }
1102
+
1103
+ this.coords2[i].push({
1104
+ object: this,
1105
+ element: rect,
1106
+ x: parseFloat(rect.getAttribute('x')),
1107
+ y: parseFloat(rect.getAttribute('y')),
1108
+ width: parseFloat(rect.getAttribute('width')),
1109
+ height: parseFloat(rect.getAttribute('height'))
1110
+ });
1111
+
1112
+
1113
+ // Add the tooltip data- attribute
1114
+ if (!RGraph.SVG.isNull(properties.tooltips) && (properties.tooltips[sequentialIndex] || typeof properties.tooltips === 'string') ) {
1115
+
1116
+ var obj = this;
1117
+
1118
+
1119
+ //
1120
+ // Add tooltip event listeners
1121
+ //
1122
+ (function (idx, seq)
1123
+ {
1124
+ var indexes = RGraph.SVG.sequentialIndexToGrouped(seq, obj.data);
1125
+
1126
+ rect.addEventListener(properties.tooltipsEvent.replace(/^on/, ''), function (e)
1127
+ {
1128
+ obj.removeHighlight();
1129
+
1130
+ // Show the tooltip
1131
+ RGraph.SVG.tooltip({
1132
+ object: obj,
1133
+ group: idx,
1134
+ index: indexes[1],
1135
+ sequentialIndex: seq,
1136
+ text: typeof properties.tooltips === 'string' ? properties.tooltips : properties.tooltips[seq],
1137
+ event: e
1138
+ });
1139
+
1140
+ // Highlight the rect that has been clicked on
1141
+ obj.highlight(e.target);
1142
+
1143
+ }, false);
1144
+
1145
+ rect.addEventListener('mousemove', function (e)
1146
+ {
1147
+ e.target.style.cursor = 'pointer'
1148
+ }, false);
1149
+ })(i, sequentialIndex);
1150
+ }
1151
+ }
1152
+
1153
+ --sequentialIndex;
1154
+
1155
+
1156
+
1157
+ //
1158
+ // STACKED CHARTS
1159
+ //
1160
+ } else if (RGraph.SVG.isArray(this.data[i]) && properties.grouping === 'stacked') {
1161
+
1162
+ // This is each bars "segment" of the chart
1163
+ var section = ( (this.graphHeight - properties.marginInnerTop - properties.marginInnerBottom) / this.data.length);
1164
+
1165
+ // Initialise the X coordinate
1166
+ var x = this.getXCoord(0);
1167
+
1168
+ // Loop through the stack
1169
+ for (var j=0; j<this.data[i].length; ++j,++sequentialIndex) {
1170
+
1171
+ var outerHeight = (this.graphHeight - properties.marginInnerTop - properties.marginInnerBottom) / this.data.length,
1172
+ width = Math.abs((this.data[i][j] / (this.max - this.min)) * this.graphWidth),
1173
+ height = outerHeight - (2 * properties.marginInner),
1174
+ y = properties.marginTop + properties.marginInner + properties.marginInnerTop + (outerHeight * i);
1175
+
1176
+ if (properties.yaxisPosition === 'right') {
1177
+ x -= width;
1178
+ }
1179
+
1180
+ // If this is the first iteration of the loop and a shadow
1181
+ // is requested draw a rect here to create it.
1182
+ if (j === 0 && properties.shadow) {
1183
+
1184
+ var fullWidth = Math.abs((RGraph.SVG.arraySum(this.data[i]) / (this.max - this.min)) * this.graphWidth);
1185
+
1186
+ var rect = RGraph.SVG.create({
1187
+ svg: this.svg,
1188
+ parent: this.svg.all,
1189
+ type: 'rect',
1190
+ attr: {
1191
+ x: properties.yaxisPosition === 'right' ? this.getXCoord(0) - fullWidth : this.getXCoord(0),
1192
+ y: y,
1193
+ width: fullWidth,
1194
+ height: height,
1195
+ fill: 'white',
1196
+ 'stroke-width': 0,
1197
+ 'data-index': i,
1198
+ filter: 'url(#dropShadow)'
1199
+ }
1200
+ });
1201
+
1202
+ this.stackedBackfaces[i] = rect;
1203
+ }
1204
+
1205
+
1206
+
1207
+ // Create the visible bar
1208
+ var rect = RGraph.SVG.create({
1209
+ svg: this.svg,
1210
+ type: 'rect',
1211
+ parent: this.svg.all,
1212
+ attr: {
1213
+ stroke: properties['colorsStroke'],
1214
+ fill: properties.colorsSequential ? (properties.colors[sequentialIndex] ? properties.colors[sequentialIndex] : properties.colors[properties.colors.length - 1]) : (properties.colors[j] ? properties.colors[j] : properties.colors[properties.colors.length - 1]),
1215
+ x: x,
1216
+ y: y,
1217
+ width: width,
1218
+ height: height,
1219
+ 'stroke-width': properties.linewidth,
1220
+ 'data-original-width': width,
1221
+ 'data-original-height': height,
1222
+ 'data-original-x': x - width,
1223
+ 'data-original-y': y,
1224
+ 'data-index': i,
1225
+ 'data-sequential-index': sequentialIndex,
1226
+ 'data-tooltip': (!RGraph.SVG.isNull(properties.tooltips) && properties.tooltips.length) ? properties.tooltips[sequentialIndex] : '',
1227
+ 'data-value': this.data[i][j]
1228
+ }
1229
+ });
1230
+
1231
+ this.coords.push({
1232
+ object: this,
1233
+ element: rect,
1234
+ x: parseFloat(rect.getAttribute('x')),
1235
+ y: parseFloat(rect.getAttribute('y')),
1236
+ width: parseFloat(rect.getAttribute('width')),
1237
+ height: parseFloat(rect.getAttribute('height'))
1238
+ });
1239
+
1240
+ if (!this.coords2[i]) {
1241
+ this.coords2[i] = [];
1242
+ }
1243
+
1244
+ this.coords2[i].push({
1245
+ object: this,
1246
+ element: rect,
1247
+ x: parseFloat(rect.getAttribute('x')),
1248
+ y: parseFloat(rect.getAttribute('y')),
1249
+ width: parseFloat(rect.getAttribute('width')),
1250
+ height: parseFloat(rect.getAttribute('height'))
1251
+ });
1252
+
1253
+
1254
+
1255
+ // Add the tooltips
1256
+ if (!RGraph.SVG.isNull(properties.tooltips) && (properties.tooltips[sequentialIndex] || typeof properties.tooltips === 'string')) {
1257
+
1258
+ var obj = this;
1259
+
1260
+
1261
+ //
1262
+ // Add tooltip event listeners
1263
+ //
1264
+ (function (idx, seq)
1265
+ {
1266
+ rect.addEventListener(properties.tooltipsEvent.replace(/^on/, ''), function (e)
1267
+ {
1268
+ obj.removeHighlight();
1269
+
1270
+ var indexes = RGraph.SVG.sequentialIndexToGrouped(seq, obj.data);
1271
+
1272
+ // Show the tooltip
1273
+ RGraph.SVG.tooltip({
1274
+ object: obj,
1275
+ index: indexes[1],
1276
+ group: idx,
1277
+ sequentialIndex: seq,
1278
+ text: typeof properties.tooltips === 'string' ? properties.tooltips : properties.tooltips[seq],
1279
+ event: e
1280
+ });
1281
+
1282
+ // Highlight the rect that has been clicked on
1283
+ obj.highlight(e.target);
1284
+ }, false);
1285
+
1286
+ rect.addEventListener('mousemove', function (e)
1287
+ {
1288
+ e.target.style.cursor = 'pointer'
1289
+ }, false);
1290
+ })(i, sequentialIndex);
1291
+ }
1292
+
1293
+
1294
+ // Adjust the X coord
1295
+ if (properties.yaxisPosition === 'right') {
1296
+ //x -= width;
1297
+ } else {
1298
+ x += width;
1299
+ }
1300
+
1301
+ }
1302
+
1303
+ --sequentialIndex;
1304
+ }
1305
+ }
1306
+
1307
+ };
1308
+
1309
+
1310
+
1311
+
1312
+
1313
+
1314
+
1315
+
1316
+
1317
+ //
1318
+ // This function can be used to retrieve the relevant X coordinate for a
1319
+ // particular value.
1320
+ //
1321
+ // @param int value The value to get the X coordinate for
1322
+ //
1323
+ this.getXCoord = function (value)
1324
+ {
1325
+ var prop = this.properties;
1326
+
1327
+ if (value > this.scale.max) {
1328
+ return null;
1329
+ }
1330
+
1331
+ if (value < this.scale.min) {
1332
+ return null;
1333
+ }
1334
+
1335
+ var x = ((value - this.scale.min) / (this.scale.max - this.scale.min));
1336
+ x *= this.graphWidth;
1337
+
1338
+ if (properties.yaxisPosition === 'right') {
1339
+ x = this.width - properties.marginRight - x;
1340
+ } else {
1341
+ x += properties.marginLeft;
1342
+ }
1343
+
1344
+ return x;
1345
+ };
1346
+
1347
+
1348
+
1349
+
1350
+
1351
+
1352
+
1353
+
1354
+
1355
+ //
1356
+ // This function can be used to retrieve the relevant X coordinate for a
1357
+ // particular value.
1358
+ //
1359
+ // @param int value The value to get the X coordinate for
1360
+ //
1361
+ this.getWidth = function (value)
1362
+ {
1363
+ if (this.scale.max <= 0 && this.scale.min < this.scale.max) {
1364
+ var x1 = this.getXCoord(this.scale.max);
1365
+ var x2 = this.getXCoord(value);
1366
+
1367
+ } else if (this.scale.min > 0 && this.scale.max > this.scale.min) {
1368
+ var x1 = this.getXCoord(this.scale.min);
1369
+ var x2 = this.getXCoord(value);
1370
+
1371
+ } else {
1372
+ var x1 = this.getXCoord(0);
1373
+ var x2 = this.getXCoord(value);
1374
+ }
1375
+
1376
+ return Math.abs(x1 - x2);
1377
+ };
1378
+
1379
+ //Math.abs(((this.data[i] - this.scale.min) / (this.max - this.scale.min)) * this.graphWidth)
1380
+
1381
+
1382
+
1383
+
1384
+
1385
+
1386
+
1387
+
1388
+ //
1389
+ // This function can be used to highlight a bar on the chart
1390
+ //
1391
+ // @param object rect The rectangle to highlight
1392
+ //
1393
+ this.highlight = function (rect)
1394
+ {
1395
+ var x = parseFloat(rect.getAttribute('x')) - 0.5,
1396
+ y = parseFloat(rect.getAttribute('y')) - 0.5,
1397
+ width = parseFloat(rect.getAttribute('width')) + 1,
1398
+ height = parseFloat(rect.getAttribute('height')) + 1;
1399
+
1400
+ var highlight = RGraph.SVG.create({
1401
+ svg: this.svg,
1402
+ type: 'rect',
1403
+ parent: this.svg.all,
1404
+ attr: {
1405
+ stroke: properties.highlightStroke,
1406
+ fill: properties.highlightFill,
1407
+ x: x,
1408
+ y: y,
1409
+ width: width,
1410
+ height: height,
1411
+ 'stroke-width': properties.highlightLinewidth
1412
+ },
1413
+ style: {
1414
+ pointerEvents: 'none'
1415
+ }
1416
+ });
1417
+
1418
+
1419
+ //if (properties.tooltipsEvent === 'mousemove') {
1420
+ // highlight.addEventListener('mouseout', function (e)
1421
+ // {
1422
+ // highlight.parentNode.removeChild(highlight);
1423
+ // RGraph.SVG.hideTooltip();
1424
+
1425
+ // RGraph.SVG.REG.set('highlight', null);
1426
+ // }, false);
1427
+ //}
1428
+
1429
+
1430
+ // Store the highlight rect in the rebistry so
1431
+ // it can be cleared later
1432
+ RGraph.SVG.REG.set('highlight', highlight);
1433
+ };
1434
+
1435
+
1436
+
1437
+
1438
+
1439
+
1440
+
1441
+
1442
+ //
1443
+ // This allows for easy specification of gradients
1444
+ //
1445
+ this.parseColors = function ()
1446
+ {
1447
+ // Save the original colors so that they can be restored when
1448
+ // the canvas is cleared
1449
+ if (!Object.keys(this.originalColors).length) {
1450
+ this.originalColors = {
1451
+ colors: RGraph.SVG.arrayClone(properties.colors),
1452
+ backgroundGridColor: RGraph.SVG.arrayClone(properties.backgroundGridColor),
1453
+ highlightFill: RGraph.SVG.arrayClone(properties.highlightFill),
1454
+ backgroundColor: RGraph.SVG.arrayClone(properties.backgroundColor)
1455
+ }
1456
+ }
1457
+
1458
+
1459
+ // colors
1460
+ var colors = properties.colors;
1461
+
1462
+ if (colors) {
1463
+ for (var i=0; i<colors.length; ++i) {
1464
+ colors[i] = RGraph.SVG.parseColorLinear({
1465
+ object: this,
1466
+ color: colors[i],
1467
+ direction: 'horizontal',
1468
+ start: properties.marginLeft,
1469
+ end: this.width - properties.marginRight
1470
+ });
1471
+ }
1472
+ }
1473
+
1474
+ properties.backgroundGridColor = RGraph.SVG.parseColorLinear({object: this, color: properties.backgroundGridColor, direction: 'horizontal',start: properties.marginLeft,end: this.width - properties.marginRight});
1475
+ properties.highlightFill = RGraph.SVG.parseColorLinear({object: this, color: properties.highlightFill, direction: 'horizontal',start: properties.marginLeft,end: this.width - properties.marginRight});
1476
+ properties.backgroundColor = RGraph.SVG.parseColorLinear({object: this, color: properties.backgroundColor});
1477
+ };
1478
+
1479
+
1480
+
1481
+
1482
+
1483
+
1484
+
1485
+
1486
+ //
1487
+ // Draws the labelsAbove
1488
+ //
1489
+ this.drawLabelsAbove = function ()
1490
+ {
1491
+ // Go through the above labels
1492
+ if (properties.labelsAbove) {
1493
+
1494
+ // Get the text configuration for the labels
1495
+ var textConf = RGraph.SVG.getTextConf({
1496
+ object: this,
1497
+ prefix: 'labelsAbove'
1498
+ });
1499
+
1500
+ var data = RGraph.SVG.arrayLinearize(this.data);
1501
+
1502
+ for (var i=0; i<this.coords.length; ++i) {
1503
+
1504
+ var value = data[i].toFixed(typeof properties.labelsAboveDecimals === 'number' ? properties.labelsAboveDecimals : properties.xaxisScaleDecimals);
1505
+ var indexes = RGraph.SVG.sequentialIndexToGrouped(i, this.data);
1506
+
1507
+
1508
+
1509
+ if (RGraph.SVG.isArray(this.data[indexes[0]]) && properties.grouping === 'stacked') {
1510
+ if ((indexes[1] + 1) === this.data[indexes[0]].length) {
1511
+ value = RGraph.SVG.arraySum(this.data[indexes[0]]);
1512
+ value = value.toFixed(typeof properties.labelsAboveDecimals === 'number' ? properties.labelsAboveDecimals : properties.xaxisScaleDecimals);
1513
+ } else {
1514
+ continue;
1515
+ }
1516
+ }
1517
+
1518
+
1519
+ var str = properties.labelsAboveSpecific ? properties.labelsAboveSpecific[i].toString() : RGraph.SVG.numberFormat({
1520
+ object: this,
1521
+ num: value,
1522
+ prepend: typeof properties.labelsAboveUnitsPre === 'string' ? properties.labelsAboveUnitsPre : null,
1523
+ append: typeof properties.labelsAboveUnitsPost === 'string' ? properties.labelsAboveUnitsPost : null,
1524
+ point: typeof properties.labelsAbovePoint === 'string' ? properties.labelsAbovePoint : null,
1525
+ thousand: typeof properties.labelsAboveThousand === 'string' ? properties.labelsAboveThousand : null,
1526
+ formatter: typeof properties.labelsAboveFormatter === 'function' ? properties.labelsAboveFormatter : null
1527
+ });
1528
+
1529
+ var halign = properties.labelsAboveHalign,
1530
+ valign = properties.labelsAboveValign;
1531
+
1532
+
1533
+ var dimensions = RGraph.SVG.measureText({
1534
+ text: str,
1535
+ bold: textConf.bold,
1536
+ font: textConf.font,
1537
+ size: textConf.size
1538
+ });
1539
+
1540
+ var x = (value >= 0)
1541
+ ? (parseFloat(this.coords[i].element.getAttribute('x')) + 7 + properties.labelsAboveOffsetx)
1542
+ : parseFloat(this.coords[i].element.getAttribute('x') - 7 - properties.labelsAboveOffsetx),
1543
+ y = parseFloat(this.coords[i].element.getAttribute('y')) + parseFloat(this.coords[i].element.getAttribute('height') / 2) + properties.labelsAboveOffsety,
1544
+ width = dimensions[0],
1545
+ height = dimensions[1],
1546
+ halign = (value >= 0) ? 'left': 'right';
1547
+
1548
+ // Corner case
1549
+ if (properties.yaxisPosition === 'left' && properties.grouping === 'grouped') {
1550
+ x = parseFloat(this.coords[i].element.getAttribute('x')) + parseFloat(this.coords[i].element.getAttribute('width')) + 7 + properties.labelsAboveOffsetx
1551
+ }
1552
+
1553
+
1554
+
1555
+
1556
+
1557
+
1558
+ // ADjust the values if the Y axis is on the RHS
1559
+ if (properties.yaxisPosition === 'right') {
1560
+ x = (value >= 0)
1561
+ ? (parseFloat(this.coords[i].element.getAttribute('x')) - 7 - properties.labelsAboveOffsetx)
1562
+ : parseFloat(this.coords[i].element.getAttribute('x') + 7 + properties.labelsAboveOffsetx),
1563
+ halign = (value >= 0) ? 'right': 'left';
1564
+
1565
+ // Special case for an oddity
1566
+ } else if (RGraph.SVG.isArray(this.data[indexes[0]]) && properties.grouping === 'stacked' && properties.yaxisPosition === 'left') {
1567
+ x += this.coords2[indexes[0]][indexes[1]].width;
1568
+ }
1569
+
1570
+ // Another corner case
1571
+ if (
1572
+ properties.yaxisPosition === 'right'
1573
+ && properties.grouping === 'grouped'
1574
+ && properties.xaxisScaleMax > 0
1575
+ && properties.xaxisScaleMin < 0
1576
+ ) {
1577
+
1578
+ var value = this.coords[i].element.getAttribute('data-value');
1579
+
1580
+ if (value < 0) {
1581
+ x = this.getXCoord(value) + 7;
1582
+ } else {
1583
+ x = this.getXCoord(value) - 7;
1584
+ }
1585
+ }
1586
+
1587
+ // Another corner case
1588
+ if (
1589
+ properties.yaxisPosition === 'left'
1590
+ && properties.grouping === 'grouped'
1591
+ && properties.xaxisScaleMax > 0
1592
+ && properties.xaxisScaleMin < 0
1593
+ ) {
1594
+
1595
+ var value = this.coords[i].element.getAttribute('data-value');
1596
+
1597
+ if (value < 0) {
1598
+ x = this.getXCoord(value) - 7;
1599
+ } else {
1600
+ x = this.getXCoord(value) + 7;
1601
+ }
1602
+ }
1603
+
1604
+
1605
+ // Account for the labels going off the edge of the SVG tag (whilst the Y axis
1606
+ // is on the left)
1607
+ if (properties.yaxisPosition === 'right') {
1608
+ if (x - width < properties.marginLeft && value > 0) {
1609
+ halign = 'left';
1610
+ x = properties.marginLeft + 5;
1611
+ properties.labelsAboveBackground = properties.labelsAboveBackground || 'rgba(255,255,255,0.95)';
1612
+ }
1613
+ } else {
1614
+ if (x + width > this.width && value > 0) {
1615
+ halign = 'right';
1616
+ x = this.width - 5;
1617
+ properties.labelsAboveBackground = properties.labelsAboveBackground || 'rgba(255,255,255,0.95)';
1618
+ }
1619
+ }
1620
+
1621
+ // Another oddity - when there's regular data but the grouping
1622
+ // is set to stacked and the Y axis is on the left
1623
+ if (properties.grouping === 'stacked' && typeof this.data[indexes[0]] === 'number' && properties.yaxisPosition === 'left') {
1624
+ x += parseInt(this.coords[i].element.getAttribute('width'));
1625
+ }
1626
+
1627
+ // Horizontal alignment
1628
+ if (typeof properties.labelsAboveHalign === 'string') {
1629
+ halign = properties.labelsAboveHalign;
1630
+ }
1631
+
1632
+ var text = RGraph.SVG.text({
1633
+
1634
+ object: this,
1635
+ parent: this.svg.all,
1636
+ tag: 'labels.above',
1637
+
1638
+ text: str,
1639
+
1640
+ x: x,
1641
+ y: y,
1642
+
1643
+ halign: halign,
1644
+ valign: valign,
1645
+
1646
+ font: textConf.font,
1647
+ size: textConf.size,
1648
+ bold: textConf.bold,
1649
+ italic: textConf.italic,
1650
+ color: textConf.color,
1651
+
1652
+ background: properties.labelsAboveBackground || null,
1653
+ padding: properties.labelsAboveBackgroundPadding || 0
1654
+ });
1655
+ }
1656
+ }
1657
+ };
1658
+
1659
+
1660
+
1661
+
1662
+
1663
+
1664
+
1665
+
1666
+ //
1667
+ // Draws the labelsInbar
1668
+ //
1669
+ this.drawLabelsInbar = function ()
1670
+ {
1671
+ // Go through the above labels
1672
+ if (properties.labelsInbar) {
1673
+
1674
+ // Default alignment
1675
+ var valign = properties.labelsInbarValign,
1676
+ halign = properties.labelsInbarHalign;
1677
+
1678
+ // Get the text configuration for the labels
1679
+ var textConf = RGraph.SVG.getTextConf({
1680
+ object: this,
1681
+ prefix: 'labelsInbar'
1682
+ });
1683
+
1684
+ var data = RGraph.SVG.arrayLinearize(this.data);
1685
+
1686
+ for (var i=0; i<this.coords.length; ++i) {
1687
+ if (RGraph.SVG.isNumber(data[i]) && !isNaN(data[i]) ) {
1688
+ // The rect element that represents the bar
1689
+ var el = this.coords[i].element;
1690
+ var value = data[i].toFixed(properties.labelsInbarDecimals);
1691
+ var indexes = RGraph.SVG.sequentialIndexToGrouped(i, this.data);
1692
+
1693
+
1694
+ var dimensions = RGraph.SVG.measureText({
1695
+ text: str,
1696
+ bold: textConf.bold,
1697
+ font: textConf.font,
1698
+ size: textConf.size
1699
+ });
1700
+
1701
+ var x = parseFloat(el.getAttribute('x')) + (parseFloat(el.getAttribute('width')) / 2) + properties.labelsInbarOffsetx,
1702
+ y = parseFloat(el.getAttribute('y')) + (parseFloat(el.getAttribute('height')) / 2) + properties.labelsInbarOffsety,
1703
+ width = dimensions[0],
1704
+ height = dimensions[1];
1705
+
1706
+ //
1707
+ // Horizontal alignment
1708
+ //
1709
+ if (properties.labelsInbarHalign === 'left') {
1710
+ halign = 'left';
1711
+ x = parseFloat(el.getAttribute('x')) + 5 + properties.labelsInbarOffsetx;
1712
+ } else if (properties.labelsInbarHalign === 'right') {
1713
+ halign = 'right';
1714
+ x = parseFloat(el.getAttribute('x')) + parseFloat(el.getAttribute('width')) - 5 + properties.labelsInbarOffsetx;
1715
+ }
1716
+
1717
+ //
1718
+ // Vertical alignment
1719
+ //
1720
+ if (properties.labelsInbarValign === 'bottom') {
1721
+ valign = 'bottom';
1722
+ y = parseFloat(el.getAttribute('y')) - 5 + parseFloat(el.getAttribute('height')) + properties.labelsInbarOffsety;
1723
+ } else if (properties.labelsInbarValign === 'top') {
1724
+ valign = 'top';
1725
+ y = parseFloat(el.getAttribute('y')) + 5 + properties.labelsInbarOffsety;
1726
+ }
1727
+
1728
+ var str = properties.labelsAboveSpecific ? properties.labelsAboveSpecific[i].toString() : RGraph.SVG.numberFormat({
1729
+ object: this,
1730
+ num: value,
1731
+ prepend: typeof properties.labelsInbarUnitsPre === 'string' ? properties.labelsInbarUnitsPre : null,
1732
+ append: typeof properties.labelsInbarUnitsPost === 'string' ? properties.labelsInbarUnitsPost : null,
1733
+ point: typeof properties.labelsInbarPoint === 'string' ? properties.labelsInbarPoint : null,
1734
+ thousand: typeof properties.labelsInbarThousand === 'string' ? properties.labelsInbarThousand : null,
1735
+ formatter: typeof properties.labelsInbarFormatter === 'function' ? properties.labelsInbarFormatter : null
1736
+ });
1737
+
1738
+ // Specific label given
1739
+ if (RGraph.SVG.isArray(properties.labelsInbarSpecific) && (RGraph.SVG.isString(properties.labelsInbarSpecific[i]) || RGraph.SVG.isNumber(properties.labelsInbarSpecific[i]))) {
1740
+ str = properties.labelsInbarSpecific[i];
1741
+ }
1742
+
1743
+ var text = RGraph.SVG.text({
1744
+ object: this,
1745
+ parent: this.svg.all,
1746
+ tag: 'labels.inbar',
1747
+ text: str,
1748
+ x: x,
1749
+ y: y,
1750
+ halign: halign,
1751
+ valign: valign,
1752
+ font: textConf.font,
1753
+ size: textConf.size,
1754
+ bold: textConf.bold,
1755
+ italic: textConf.italic,
1756
+ color: textConf.color,
1757
+ background: properties.labelsInbarBackground || null,
1758
+ padding: properties.labelsInbarBackgroundPadding || 0
1759
+ });
1760
+ }
1761
+ }
1762
+ }
1763
+ };
1764
+
1765
+
1766
+
1767
+
1768
+
1769
+
1770
+
1771
+
1772
+ //
1773
+ // Using a function to add events makes it easier to facilitate method
1774
+ // chaining
1775
+ //
1776
+ // @param string type The type of even to add
1777
+ // @param function func
1778
+ //
1779
+ this.on = function (type, func)
1780
+ {
1781
+ if (type.substr(0,2) !== 'on') {
1782
+ type = 'on' + type;
1783
+ }
1784
+
1785
+ RGraph.SVG.addCustomEventListener(this, type, func);
1786
+
1787
+ return this;
1788
+ };
1789
+
1790
+
1791
+
1792
+
1793
+
1794
+
1795
+
1796
+
1797
+ //
1798
+ // Used in chaining. Runs a function there and then - not waiting for
1799
+ // the events to fire (eg the onbeforedraw event)
1800
+ //
1801
+ // @param function func The function to execute
1802
+ //
1803
+ this.exec = function (func)
1804
+ {
1805
+ func(this);
1806
+
1807
+ return this;
1808
+ };
1809
+
1810
+
1811
+
1812
+
1813
+
1814
+
1815
+
1816
+
1817
+ //
1818
+ // Remove highlight from the chart (tooltips)
1819
+ //
1820
+ this.removeHighlight = function ()
1821
+ {
1822
+ //var highlight = RGraph.SVG.REG.get('highlight');
1823
+ //if (highlight && highlight.parentNode) {
1824
+ // highlight.parentNode.removeChild(highlight);
1825
+ //}
1826
+
1827
+ //RGraph.SVG.REG.set('highlight', null);
1828
+
1829
+ RGraph.SVG.removeHighlight();
1830
+ };
1831
+
1832
+
1833
+
1834
+
1835
+
1836
+
1837
+
1838
+
1839
+ //
1840
+ // The Bar chart grow effect
1841
+ //
1842
+ this.grow = function ()
1843
+ {
1844
+ var opt = arguments[0] || {},
1845
+ frames = opt.frames || 30,
1846
+ frame = 0,
1847
+ obj = this,
1848
+ data = [],
1849
+ height = null,
1850
+ seq = 0;
1851
+
1852
+ //
1853
+ // Copy the data
1854
+ //
1855
+ data = RGraph.SVG.arrayClone(this.data);
1856
+
1857
+ this.draw();
1858
+
1859
+ var iterate = function ()
1860
+ {
1861
+ for (var i=0,seq=0,len=obj.coords.length; i<len; ++i, ++seq) {
1862
+
1863
+ var multiplier = (frame / frames)
1864
+ // RGraph.SVG.FX.getEasingMultiplier(frames, frame)
1865
+ // RGraph.SVG.FX.getEasingMultiplier(frames, frame);
1866
+
1867
+
1868
+
1869
+
1870
+ // TODO Go through the data and update the value according to
1871
+ // the frame number
1872
+ if (typeof data[i] === 'number') {
1873
+
1874
+ width = Math.abs(obj.getXCoord(data[i]) - obj.getXCoord(0));
1875
+ obj.data[i] = data[i] * multiplier;
1876
+ width = multiplier * width;
1877
+
1878
+ // Set the new width on the rect
1879
+ obj.coords[seq].element.setAttribute(
1880
+ 'width',
1881
+ width
1882
+ );
1883
+
1884
+ // Set the correct Y coord on the object
1885
+ obj.coords[seq].element.setAttribute(
1886
+ 'x',
1887
+ data[i] > 0
1888
+ ? obj.getXCoord(0) - (properties.yaxisPosition === 'right' ? width : 0)
1889
+ : (properties.xaxisScaleMin < 0 && properties.xaxisScaleMax > 0 ? (properties.yaxisPosition === 'right' ? obj.getXCoord(0) : obj.getXCoord(0) - width) : obj.getXCoord(0))
1890
+ );
1891
+
1892
+ } else if (typeof data[i] === 'object') {
1893
+
1894
+ var accumulativeWidth = 0;
1895
+
1896
+ for (var j=0,len2=data[i].length; j<len2; ++j, ++seq) {
1897
+
1898
+ width = Math.abs(obj.getXCoord(data[i][j]) - obj.getXCoord(0));
1899
+ width = multiplier * width;
1900
+ obj.data[i][j] = data[i][j] * multiplier;
1901
+
1902
+ accumulativeWidth += width;
1903
+
1904
+ obj.coords[seq].element.setAttribute(
1905
+ 'width',
1906
+ width
1907
+ );
1908
+
1909
+ if (properties.yaxisPosition === 'right') {
1910
+ if (properties.grouping === 'stacked') {
1911
+ obj.coords[seq].element.setAttribute(
1912
+ 'x',
1913
+ obj.getXCoord(0) - accumulativeWidth
1914
+ );
1915
+ } else {
1916
+ obj.coords[seq].element.setAttribute(
1917
+ 'x',
1918
+ obj.getXCoord(0) - (obj.coords[seq].element.getAttribute('data-value') < 0 ? 0 : width)
1919
+ );
1920
+ }
1921
+
1922
+ } else {
1923
+
1924
+ obj.coords[seq].element.setAttribute(
1925
+ 'x',
1926
+ properties.grouping === 'stacked'
1927
+ ? obj.getXCoord(0) + (accumulativeWidth - width)
1928
+ : properties.grouping === 'grouped' && obj.coords[seq].element.getAttribute('data-value') < 0 ? obj.getXCoord(0) - width : obj.getXCoord(0)
1929
+ );
1930
+ }
1931
+ }
1932
+
1933
+ //
1934
+ // Set the height and Y cooord of the backfaces if necessary
1935
+ //
1936
+ if (obj.stackedBackfaces[i]) {
1937
+ obj.stackedBackfaces[i].setAttribute(
1938
+ 'width',
1939
+ accumulativeWidth
1940
+ );
1941
+
1942
+ obj.stackedBackfaces[i].setAttribute(
1943
+ 'x',
1944
+ properties.yaxisPosition === 'right' ? obj.getXCoord(0) - accumulativeWidth : obj.getXCoord(0)
1945
+ );
1946
+ }
1947
+
1948
+ // Decrease seq by one so that it's not incremented twice
1949
+ --seq;
1950
+ }
1951
+ }
1952
+
1953
+ if (frame++ < frames) {
1954
+ //setTimeout(iterate, frame > 1 ? opt.delay : 200);
1955
+ RGraph.SVG.FX.update(iterate);
1956
+ } else if (opt.callback) {
1957
+ RGraph.SVG.redraw();
1958
+ (opt.callback)(obj);
1959
+ }
1960
+ };
1961
+
1962
+ iterate();
1963
+
1964
+ return this;
1965
+ };
1966
+
1967
+
1968
+
1969
+
1970
+
1971
+
1972
+
1973
+
1974
+ //
1975
+ // HBar chart Wave effect.
1976
+ //
1977
+ // @param object OPTIONAL An object map of options. You specify 'frames'
1978
+ // here to give the number of frames in the effect
1979
+ // and also callback to specify a callback function
1980
+ // thats called at the end of the effect
1981
+ //
1982
+ // **************************************************************
1983
+ // *** In order to deal with stacked charts, this function is ***
1984
+ // *** complicated - probably significantly more so than it ***
1985
+ // *** needs to be. As such it most definitely needs ***
1986
+ // *** refactoring ***
1987
+ // **************************************************************
1988
+ //
1989
+ this.wave = function ()
1990
+ {
1991
+ var stackedAccumulativeWidth = 0;
1992
+
1993
+ // First draw the chart
1994
+ this.draw();
1995
+
1996
+
1997
+ var obj = this,
1998
+ opt = arguments[0] || {};
1999
+
2000
+ opt.frames = opt.frames || 60;
2001
+ opt.startFrames = [];
2002
+ opt.counters = [];
2003
+
2004
+ var framesperbar = opt.frames / 3,
2005
+ frame = -1,
2006
+ callback = opt.callback || function () {},
2007
+ width;
2008
+
2009
+ for (var i=0,len=this.coords.length; i<len; i+=1) {
2010
+ opt.startFrames[i] = ((opt.frames / 2) / (obj.coords.length - 1)) * i;
2011
+ opt.counters[i] = 0;
2012
+
2013
+ // Now zero the width of the bar
2014
+ this.coords[i].element.setAttribute('width', 0);
2015
+
2016
+ // Use this loop to set the stackedBackfaces to 0 width
2017
+ if (properties.grouping === 'stacked' && obj.stackedBackfaces[i]) {
2018
+ obj.stackedBackfaces[i].setAttribute('width', 0);
2019
+ }
2020
+ }
2021
+
2022
+ // Edge-case
2023
+ if (properties.grouping === 'stacked' && properties.yaxisPosition === 'right') {
2024
+ previousX = obj.width - properties.marginRight;
2025
+ previousW = 0;
2026
+ }
2027
+
2028
+
2029
+ function iterator ()
2030
+ {
2031
+ ++frame;
2032
+ var group = 0;
2033
+
2034
+ for (var i=0,len=obj.coords.length; i<len; i+=1) {
2035
+ if (frame > opt.startFrames[i]) {
2036
+
2037
+ var originalWidth = obj.coords[i].element.getAttribute('data-original-width'),
2038
+ value = parseFloat(obj.coords[i].element.getAttribute('data-value')),
2039
+ seq = i;
2040
+ indexes = RGraph.SVG.sequentialIndexToGrouped(i, obj.data);
2041
+
2042
+ if (indexes[0] !== group) {
2043
+ group = indexes[0];
2044
+ }
2045
+
2046
+ obj.coords[i].element.setAttribute(
2047
+ 'width',
2048
+ width = Math.min(
2049
+ ((frame - opt.startFrames[i]) / framesperbar) * originalWidth,
2050
+ originalWidth
2051
+ )
2052
+ );
2053
+
2054
+ stackedAccumulativeWidth += width;
2055
+
2056
+ if (properties.yaxisPosition === 'right') {
2057
+ if (properties.grouping === 'stacked') {
2058
+
2059
+ if (indexes[1] === 0) {
2060
+ obj.coords[i].element.setAttribute('x',obj.width - properties.marginRight - width);
2061
+
2062
+ var previousX = obj.coords[i].element.getAttribute('x');
2063
+ } else {
2064
+ obj.coords[i].element.setAttribute(
2065
+ 'x',
2066
+ previousX - width
2067
+ );
2068
+ }
2069
+
2070
+
2071
+ } else {
2072
+ obj.coords[i].element.setAttribute(
2073
+ 'x',
2074
+ value >=0
2075
+ ? obj.getXCoord(0) - width
2076
+ : obj.getXCoord(0)
2077
+ );
2078
+ }
2079
+ } else {
2080
+ obj.coords[i].element.setAttribute(
2081
+ 'x',
2082
+ value >=0 ? obj.getXCoord(0) : obj.getXCoord(0) - width
2083
+ );
2084
+ }
2085
+
2086
+
2087
+ if (properties.grouping === 'stacked' && RGraph.SVG.isArray(obj.data[indexes[0]])) {
2088
+
2089
+ // Are these two needed any more? //
2090
+ //var seq = obj.coords[i].element.getAttribute('data-sequential-index');
2091
+ //var indexes = RGraph.SVG.sequentialIndexToGrouped(seq, obj.data);
2092
+ ////////////////////////////////////
2093
+
2094
+ if (properties.yaxisPosition === 'left' && indexes[1] > 0) {
2095
+ obj.coords[i].element.setAttribute(
2096
+ 'x',
2097
+ parseInt(obj.coords[i - 1].element.getAttribute('x')) + parseInt(obj.coords[i - 1].element.getAttribute('width'))
2098
+ );
2099
+ }
2100
+
2101
+ // Not really related to the code above, reuse this if()
2102
+ // condition to set the width of the backface
2103
+ //obj.stackedBackfaces[indexes[0]].setAttribute('width', width);
2104
+ for (var j=0,cumulativeWidth=0; j<obj.coords2[indexes[0]].length; ++j) {
2105
+ cumulativeWidth += parseInt(obj.coords2[indexes[0]][j].element.getAttribute('width'))
2106
+ }
2107
+
2108
+ if (properties.yaxisPosition === 'right') {
2109
+ obj.stackedBackfaces[indexes[0]].setAttribute('width', cumulativeWidth);
2110
+ obj.stackedBackfaces[indexes[0]].setAttribute('x', obj.width - properties.marginRight - cumulativeWidth);
2111
+ } else {
2112
+
2113
+ obj.stackedBackfaces[indexes[0]].setAttribute('x', obj.getXCoord(0));
2114
+
2115
+ obj.stackedBackfaces[indexes[0]].setAttribute(
2116
+ 'width',
2117
+ cumulativeWidth
2118
+ );
2119
+ }
2120
+
2121
+ previousX = obj.coords[i].element.getAttribute('x');
2122
+ previousW = obj.coords[i].element.getAttribute('width');
2123
+ }
2124
+ }
2125
+ }
2126
+
2127
+
2128
+ if (frame >= opt.frames) {
2129
+ callback(obj);
2130
+ } else {
2131
+ RGraph.SVG.FX.update(iterator);
2132
+ }
2133
+ }
2134
+
2135
+ iterator();
2136
+
2137
+ return this;
2138
+ };
2139
+
2140
+
2141
+
2142
+
2143
+
2144
+
2145
+
2146
+
2147
+ //
2148
+ // A worker function that handles Bar chart specific tooltip substitutions
2149
+ //
2150
+ this.tooltipSubstitutions = function (opt)
2151
+ {
2152
+ var indexes = RGraph.SVG.sequentialIndexToGrouped(opt.index, this.data);
2153
+
2154
+ return {
2155
+ index: indexes[1],
2156
+ dataset: indexes[0],
2157
+ sequentialIndex: opt.index,
2158
+ value: typeof this.data[indexes[0]] === 'number' ? this.data[indexes[0]] : this.data[indexes[0]][indexes[1]],
2159
+ values: typeof this.data[indexes[0]] === 'number' ? [this.data[indexes[0]]] : this.data[indexes[0]]
2160
+ };
2161
+ };
2162
+
2163
+
2164
+
2165
+
2166
+
2167
+
2168
+
2169
+
2170
+ //
2171
+ // A worker function that returns the correct color/label/value
2172
+ //
2173
+ // @param object specific The indexes that are applicable
2174
+ // @param number index The appropriate index
2175
+ //
2176
+ this.tooltipsFormattedCustom = function (specific, index)
2177
+ {
2178
+ if (typeof this.data[0] === 'object') {
2179
+ var label = (!RGraph.SVG.isNull(properties.tooltipsFormattedKeyLabels) && typeof properties.tooltipsFormattedKeyLabels === 'object' && properties.tooltipsFormattedKeyLabels[index])
2180
+ ? properties.tooltipsFormattedKeyLabels[index]
2181
+ : '';
2182
+
2183
+ } else {
2184
+ var label = (!RGraph.SVG.isNull(properties.tooltipsFormattedKeyLabels) && typeof properties.tooltipsFormattedKeyLabels === 'object' && properties.tooltipsFormattedKeyLabels[specific.index])
2185
+ ? properties.tooltipsFormattedKeyLabels[specific.index]
2186
+ : '';
2187
+ }
2188
+
2189
+
2190
+ return {
2191
+ label: label
2192
+ };
2193
+ };
2194
+
2195
+
2196
+
2197
+
2198
+
2199
+
2200
+
2201
+
2202
+ //
2203
+ // This allows for static tooltip positioning
2204
+ //
2205
+ this.positionTooltipStatic = function (args)
2206
+ {
2207
+ var obj = args.object,
2208
+ e = args.event,
2209
+ tooltip = args.tooltip,
2210
+ index = args.index,
2211
+ svgXY = RGraph.SVG.getSVGXY(obj.svg),
2212
+ coords = this.coords[args.index];
2213
+
2214
+ // Position the tooltip in the X direction
2215
+ args.tooltip.style.left = (
2216
+ svgXY[0] // The X coordinate of the canvas
2217
+ + coords.x // The X coordinate of the bar on the chart
2218
+ - (tooltip.offsetWidth / 2) // Subtract half of the tooltip width
2219
+ + (coords.width / 2) // Add half of the bar width
2220
+ ) + 'px';
2221
+
2222
+ args.tooltip.style.top = (
2223
+ svgXY[1] // The Y coordinate of the canvas
2224
+ + coords.y // The Y coordinate of the bar on the chart
2225
+ - tooltip.offsetHeight // The height of the tooltip
2226
+ - 10 // An arbitrary amount
2227
+ ) + 'px';
2228
+ };
2229
+
2230
+
2231
+
2232
+
2233
+
2234
+
2235
+
2236
+
2237
+ //
2238
+ // Draw a line on the chart - just each of the X points
2239
+ // (ie the top of the bars) connected by a line. This
2240
+ // does mean you can set the colors property to transparent
2241
+ // and you have a vertical line.
2242
+ //
2243
+ this.drawLine = function ()
2244
+ {
2245
+ // Set the clipping region so that the trace
2246
+ //effect works
2247
+ //RGraph.clipTo.start(this, [
2248
+ // 0,0,
2249
+ // this.canvas.width,this.canvas.height * this.properties.animationTraceClip
2250
+ //]);
2251
+
2252
+ if (this.properties.lineShadow) {
2253
+ RGraph.SVG.setShadow({
2254
+ object: this,
2255
+ id: 'lineDropShadow_' + this.uid,
2256
+ offsetx: this.properties.lineShadowOffsetx,
2257
+ offsety: this.properties.lineShadowOffsety,
2258
+ blur: this.properties.lineShadowBlur,
2259
+ color: this.properties.lineShadowColor
2260
+ });
2261
+ }
2262
+
2263
+ if (this.properties.lineSpline) {
2264
+
2265
+ // Set this so that we can refer to the object
2266
+ var obj = this;
2267
+ var c = RGraph.SVG.arrayClone(this.coords);
2268
+
2269
+ Spline(c);
2270
+
2271
+ } else {
2272
+
2273
+ // TODO Need to skip null values at the start
2274
+ // of the array here
2275
+
2276
+ var d = '';
2277
+
2278
+ // Move to the first coordinate
2279
+ if (RGraph.SVG.isNumber(this.data[0])) {
2280
+ if (this.properties.yaxisPosition === 'right') {
2281
+ d = 'M {1} {2} '.format(
2282
+ this.coords[0].x,
2283
+ this.coords[0].y + (this.coords[0].height / 2)
2284
+ );
2285
+ } else {
2286
+ d = 'M {1} {2} '.format(
2287
+ this.coords[0].x + this.coords[0].width,
2288
+ this.coords[0].y + (this.coords[0].height / 2)
2289
+ );
2290
+ }
2291
+ }
2292
+
2293
+ // Draw a line to subsequent points unless
2294
+ // that point is null, in which case move
2295
+ // to it instead
2296
+ for (let i=0; i<this.coords.length; ++i) {
2297
+
2298
+ if (RGraph.SVG.isNull(this.data[i])) {
2299
+ var action = 'M';
2300
+ var x = 0;
2301
+ var y = 0;
2302
+ } else if (RGraph.SVG.isNull(this.data[i - 1])) {
2303
+ var action = 'M';
2304
+ var x = this.coords[i].x + (this.properties.yaxisPosition === 'right' ? 0 : this.coords[i].width);
2305
+ var y = this.coords[i].y + (this.coords[i].height / 2);
2306
+ } else {
2307
+ var action = 'L';
2308
+ var x = this.coords[i].x + (this.properties.yaxisPosition === 'right' ? 0 : this.coords[i].width);
2309
+ var y = this.coords[i].y + (this.coords[i].height / 2);
2310
+ }
2311
+
2312
+ d +=
2313
+ '{1} {2} {3} '.format(
2314
+ action,x, y
2315
+ );
2316
+ }
2317
+
2318
+
2319
+ var path = RGraph.SVG.create({
2320
+ svg: this.svg,
2321
+ type: 'path',
2322
+ parent: this.svg.all,
2323
+ attr: {
2324
+ d: d,
2325
+ stroke: this.properties.lineColor,
2326
+ fill: 'transparent',
2327
+ 'stroke-width': this.properties.lineLinewidth,
2328
+ 'stroke-linecap': this.properties.lineLinecap,
2329
+ 'stroke-linejoin': this.properties.lineLinejoin,
2330
+ filter: this.properties.lineShadow ? 'url(#lineDropShadow_' + this.uid + ')' : '',
2331
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
2332
+ }
2333
+ });
2334
+
2335
+ }
2336
+
2337
+
2338
+
2339
+
2340
+
2341
+
2342
+
2343
+
2344
+
2345
+
2346
+
2347
+ //
2348
+ // TODO Add more styles of tickmarks
2349
+ //
2350
+ var obj = this;
2351
+ this.coords.forEach(function (v, k, arr)
2352
+ {
2353
+ if (typeof obj.properties.lineTickmarksStyle === 'string') {
2354
+
2355
+ var isEndTick = (k === 0 || k === (arr.length - 1));
2356
+ var isNull = RGraph.SVG.isNull(obj.data[k]);
2357
+ var prevIsNull = RGraph.SVG.isNull(obj.data[k - 1]);
2358
+ var nextIsNull = RGraph.SVG.isNull(obj.data[k + 1]);
2359
+ var isLast = k === (arr.length - 1);
2360
+
2361
+ //
2362
+ // Does this tickmark need to be drawn?
2363
+ //
2364
+ if (isNull && !obj.properties.lineTickmarksDrawNull) return;
2365
+ if (!isNull && prevIsNull && nextIsNull && !obj.properties.lineTickmarksDrawNonNull) return;
2366
+
2367
+ //
2368
+ // Draw the various styles of tickmark
2369
+ //
2370
+ switch (obj.properties.lineTickmarksStyle) {
2371
+ case 'circle':
2372
+ case 'filledcircle':
2373
+ case 'filledendcircle':
2374
+ case 'endcircle':
2375
+ if (
2376
+ (obj.properties.lineTickmarksStyle.indexOf('end') >= 0 && isEndTick)
2377
+ || obj.properties.lineTickmarksStyle.indexOf('end') === -1
2378
+ ) {
2379
+
2380
+ RGraph.SVG.create({
2381
+ svg: obj.svg,
2382
+ type: 'circle',
2383
+ parent: obj.svg.all,
2384
+ attr: {
2385
+ cx: v.x + (obj.properties.yaxisPosition === 'right' ? 0 : v.width),
2386
+ cy: v.y + (v.height/2),
2387
+ r: obj.properties.lineTickmarksSize,
2388
+ fill: obj.properties.lineColor,
2389
+ filter: obj.properties.lineShadow ? 'url(#lineDropShadow_' + obj.uid + ')' : '',
2390
+ 'clip-path': obj.isTrace ? 'url(#trace-effect-clip)' : ''
2391
+ }
2392
+ });
2393
+
2394
+ // Draw the center part of the circle tickmark
2395
+ if (obj.properties.lineTickmarksStyle.indexOf('filled') < 0) {
2396
+
2397
+ RGraph.SVG.create({
2398
+ svg: obj.svg,
2399
+ type: 'circle',
2400
+ parent: obj.svg.all,
2401
+ attr: {
2402
+ cx: v.x + (obj.properties.yaxisPosition === 'right' ? 0 : v.width),
2403
+ cy: v.y + (v.height/2),
2404
+ r: RGraph.SVG.isNumber(obj.properties.lineTickmarksLinewidth)
2405
+ ? (obj.properties.lineTickmarksSize - obj.properties.lineTickmarksLinewidth)
2406
+ : (obj.properties.lineTickmarksSize - 3),
2407
+ fill: 'white',
2408
+ 'clip-path':obj.isTrace ? 'url(#trace-effect-clip)' : ''
2409
+ }
2410
+ });
2411
+ }
2412
+ }
2413
+ break;
2414
+
2415
+ case 'square':
2416
+ case 'rect':
2417
+ case 'filledsquare':
2418
+ case 'filledrect':
2419
+ case 'filledendsquare':
2420
+ case 'filledendrect':
2421
+ case 'endsquare':
2422
+ case 'endrect':
2423
+ if (
2424
+ (obj.properties.lineTickmarksStyle.indexOf('end') >= 0 && isEndTick)
2425
+ || obj.properties.lineTickmarksStyle.indexOf('end') === -1
2426
+ ) {
2427
+ RGraph.SVG.create({
2428
+ svg: obj.svg,
2429
+ type: 'rect',
2430
+ parent: obj.svg.all,
2431
+ attr: {
2432
+ x: v.x + (obj.properties.yaxisPosition === 'right' ? 0 : v.width) - obj.properties.lineTickmarksSize,
2433
+ y: v.y + (v.height / 2) - obj.properties.lineTickmarksSize,
2434
+ width: obj.properties.lineTickmarksSize * 2,
2435
+ height: obj.properties.lineTickmarksSize * 2,
2436
+ fill: obj.properties.lineColor,
2437
+ filter: obj.properties.lineShadow ? 'url(#lineDropShadow_' + obj.uid + ')' : '',
2438
+ 'clip-path': obj.isTrace ? 'url(#trace-effect-clip)' : ''
2439
+ }
2440
+ });
2441
+
2442
+ // Draw the center part of the rect tickmark
2443
+ if (obj.properties.lineTickmarksStyle.indexOf('filled') < 0) {
2444
+ RGraph.SVG.create({
2445
+ svg: obj.svg,
2446
+ type: 'rect',
2447
+ parent: obj.svg.all,
2448
+ attr: {
2449
+ x: v.x + (obj.properties.yaxisPosition === 'right' ? 0 : v.width) - (obj.properties.lineTickmarksSize) + (RGraph.SVG.isNull(obj.properties.lineTickmarksLinewidth) ? 3 : obj.properties.lineTickmarksLinewidth),
2450
+ y: v.y + (v.height / 2) - (obj.properties.lineTickmarksSize) + (RGraph.SVG.isNull(obj.properties.lineTickmarksLinewidth) ? 3 : obj.properties.lineTickmarksLinewidth),
2451
+ width: RGraph.SVG.isNumber(obj.properties.lineTickmarksLinewidth)
2452
+ ? (obj.properties.lineTickmarksSize * 2) - (2 * obj.properties.lineTickmarksLinewidth)
2453
+ : (obj.properties.lineTickmarksSize * 2) - 3 - 3,
2454
+ height: RGraph.SVG.isNumber(obj.properties.lineTickmarksLinewidth)
2455
+ ? (obj.properties.lineTickmarksSize * 2) - (2 * obj.properties.lineTickmarksLinewidth)
2456
+ : (obj.properties.lineTickmarksSize * 2) - 3 - 3,
2457
+ fill: 'white',
2458
+ 'clip-path': obj.isTrace ? 'url(#trace-effect-clip)' : ''
2459
+ }
2460
+ });
2461
+ }
2462
+ }
2463
+ break;
2464
+ }
2465
+ }
2466
+ });
2467
+
2468
+
2469
+
2470
+
2471
+
2472
+
2473
+ //
2474
+ // This function draws a spline using the HBar coords
2475
+ //
2476
+ // @param array coords The coordinates
2477
+ //
2478
+ function Spline (coords)
2479
+ {
2480
+ obj.coordsSpline[0] = [];
2481
+
2482
+ var yCoords = [],
2483
+ interval = (obj.height - obj.properties.marginTop - obj.properties.marginBottom) / coords.length;
2484
+ path = [];
2485
+
2486
+ //
2487
+ // The drawSpline function needs an array of JUST
2488
+ // the X values - so put the coords into the correct
2489
+ // format
2490
+ //
2491
+
2492
+ for (var i=0; i<coords.length;++i) {
2493
+ coords[i] = Number(coords[i].x) + (obj.properties.yaxisPosition === 'right' ? 0 : Number(coords[i].width));
2494
+ }
2495
+
2496
+
2497
+
2498
+
2499
+ //
2500
+ // Get the Points array in the format we want -
2501
+ // first value should be null along with the lst
2502
+ // value
2503
+ //
2504
+ var P = [coords[0]];
2505
+ for (var i=0; i<coords.length; ++i) {
2506
+ P.push(coords[i]);
2507
+ }
2508
+ P.push(
2509
+ coords[coords.length - 1] + (coords[coords.length - 1] - coords[coords.length - 2])
2510
+ );
2511
+
2512
+ // This is is necessary to center the points
2513
+ // within each bar/section
2514
+ var halfsection = ((obj.height - obj.properties.marginTop - obj.properties.marginBottom) / obj.data.length) / 2
2515
+
2516
+ for (var j=1; j<P.length-2; ++j) {
2517
+ for (var t=0; t<10; ++t) {
2518
+
2519
+ var xCoord = Spline( t/10, P[j-1], P[j], P[j+1], P[j+2] );
2520
+
2521
+ yCoords.push(
2522
+ ((j-1) * interval) + (t * (interval / 10)) + obj.properties.marginTop + halfsection
2523
+ );
2524
+
2525
+ path.push([
2526
+ xCoord,
2527
+ yCoords[yCoords.length - 1]
2528
+ ]);
2529
+
2530
+
2531
+ if (typeof index == 'number') {
2532
+ obj.coordsSpline[0].push([
2533
+ xCoords[xCoords.length - 1],
2534
+ yCoords[yCoords.length - 1]
2535
+ ]);
2536
+ }
2537
+ }
2538
+ }
2539
+
2540
+
2541
+ // Draw the last section
2542
+ var last = [
2543
+ obj.coords[obj.coords.length - 1].x + (obj.properties.yaxisPosition === 'right' ? 0 : obj.coords[obj.coords.length - 1].width),
2544
+ obj.coords[obj.coords.length - 1].y + (obj.coords[obj.coords.length - 1].height / 2)
2545
+ ];
2546
+
2547
+ path.push([
2548
+ last[0],
2549
+ last[1]
2550
+ ]);
2551
+
2552
+ if (typeof index === 'number') {
2553
+ obj.coordsSpline[0].push([
2554
+ last[0],
2555
+ last[1]
2556
+ ]);
2557
+ }
2558
+
2559
+ var str = '';
2560
+ path.forEach(function (v,k,arr)
2561
+ {
2562
+ var command = (k === 0 ? 'M' : 'L');
2563
+ str += ' {1} {2} {3}'.format(command, v[0], v[1]);
2564
+ });
2565
+
2566
+
2567
+
2568
+ //
2569
+ // Create the path which depicts the spline
2570
+ //
2571
+
2572
+ RGraph.SVG.create({
2573
+ svg: obj.svg,
2574
+ parent: obj.svg.all,
2575
+ type: 'path',
2576
+ attr: {
2577
+ fill: "transparent",
2578
+ stroke: obj.properties.lineColor,
2579
+ 'stroke-width': obj.properties.lineLinewidth,
2580
+ 'stroke-linejoin': 'round',
2581
+ 'stroke-linecap': 'round',
2582
+ d: str,
2583
+ filter: obj.properties.lineShadow ? 'url(#lineDropShadow_' + obj.uid + ')' : '',
2584
+ 'clip-path': obj.isTrace ? 'url(#trace-effect-clip)' : ''
2585
+ }
2586
+ });
2587
+
2588
+
2589
+
2590
+ function Spline (t, P0, P1, P2, P3)
2591
+ {
2592
+ return 0.5 * ((2 * P1) +
2593
+ ((0-P0) + P2) * t +
2594
+ ((2*P0 - (5*P1) + (4*P2) - P3) * (t*t) +
2595
+ ((0-P0) + (3*P1)- (3*P2) + P3) * (t*t*t)));
2596
+ }
2597
+ }
2598
+ };
2599
+
2600
+
2601
+
2602
+
2603
+
2604
+
2605
+
2606
+
2607
+ //
2608
+ // A trace effect for the line
2609
+ //
2610
+ // @param object Options to give to the effect
2611
+ // @param function A function to call when the effect has completed
2612
+ //
2613
+ this.trace = function ()
2614
+ {
2615
+ var opt = arguments[0] || {},
2616
+ frame = 1,
2617
+ frames = opt.frames || 60,
2618
+ obj = this;
2619
+
2620
+ this.isTrace = true;
2621
+
2622
+ this.draw();
2623
+
2624
+
2625
+
2626
+ // Create the clip area
2627
+
2628
+ var clippath = RGraph.SVG.create({
2629
+ svg: this.svg,
2630
+ type: 'clipPath',
2631
+ parent: this.svg.defs,
2632
+ attr: {
2633
+ id: 'trace-effect-clip'
2634
+ }
2635
+ });
2636
+
2637
+ var clippathrect = RGraph.SVG.create({
2638
+ svg: this.svg,
2639
+ type: 'rect',
2640
+ parent: clippath,
2641
+ attr: {
2642
+ x: 0,
2643
+ y: 0,
2644
+ width: this.width,
2645
+ height: 0
2646
+ }
2647
+ });
2648
+
2649
+ var iterator = function ()
2650
+ {
2651
+ var height = (frame++) / frames * obj.height;
2652
+
2653
+ clippathrect.setAttribute("height", height);
2654
+
2655
+ if (frame <= frames) {
2656
+ RGraph.SVG.FX.update(iterator);
2657
+ } else {
2658
+
2659
+ // Remove the clippath
2660
+ clippath.parentNode.removeChild(clippath);
2661
+
2662
+ if (opt.callback) {
2663
+ (opt.callback)(obj);
2664
+ }
2665
+ }
2666
+ };
2667
+
2668
+ iterator();
2669
+
2670
+ return this;
2671
+ };
2672
+
2673
+
2674
+
2675
+
2676
+
2677
+
2678
+
2679
+
2680
+ //
2681
+ // Set the options that the user has provided
2682
+ //
2683
+ for (i in conf.options) {
2684
+ if (typeof i === 'string') {
2685
+ this.set(i, conf.options[i]);
2686
+ }
2687
+ }
2688
+ };
2689
+
2690
+ return this;
2691
+
2692
+ // End module pattern
2693
+ })(window, document);