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,163 +1,3959 @@
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
11
+ //
1
12
 
2
- RGraph=window.RGraph||{isRGraph:true};RGraph.Bipolar=function(conf)
3
- {if(typeof conf==='object'&&typeof conf.left==='object'&&typeof conf.right==='object'&&typeof conf.id==='string'){var id=conf.id,canvas=document.getElementById(id),left=conf.left,right=conf.right,parseConfObjectForOptions=true}else{var id=conf,canvas=document.getElementById(id),left=arguments[1],right=arguments[2]}
4
- this.id=id;this.canvas=canvas;this.context=this.canvas.getContext('2d');this.canvas.__object__=this;this.type='bipolar';this.coords=[];this.coords2=[];this.coordsLeft=[];this.coordsRight=[];this.coords2Left=[];this.coords2Right=[];this.max=0;this.isRGraph=true;this.uid=RGraph.CreateUID();this.canvas.uid=this.canvas.uid?this.canvas.uid:RGraph.CreateUID();this.coordsText=[];this.original_colors=[];this.firstDraw=true;this.propertyNameAliases={};var data=[left,right];for(var i=0;i<2;++i){data[i].forEach(function(v,k,arr)
5
- {if(RGraph.isNull(v)){}else if(typeof v==='object'){v.forEach(function(v2,k2,arr2)
6
- {arr[k][k2]=parseFloat(v2);});}else{arr[k]=parseFloat(v);}
7
- arr[k]=RGraph.stringsToNumbers(arr[k]);});}
8
- this.left=left;this.right=right;this.data=[left,right];this.properties={'chart.background.grid':true,'chart.background.grid.color':'#ddd','chart.background.grid.vlines':true,'chart.background.grid.hlines':true,'chart.background.grid.linewidth':1,'chart.background.grid.vlines.count':null,'chart.background.grid.hlines.count':null,'chart.vmargin':5,'chart.vmargin.grouped':3,'chart.xaxis':true,'chart.xaxis.tickmarks.count':5,'chart.xaxis.tickmarks.interval':null,'chart.xaxis.scale.units.pre':'','chart.xaxis.scale.units.post':'','chart.xaxis.scale.max':null,'chart.xaxis.scale.min':0,'chart.xaxis.scale.zerostart':true,'chart.xaxis.scale.decimals':null,'chart.xaxis.scale.point':'.','chart.xaxis.scale.thousand':',','chart.xaxis.labels':true,'chart.xaxis.labels.font':null,'chart.xaxis.labels.size':null,'chart.xaxis.labels.color':null,'chart.xaxis.labels.bold':null,'chart.xaxis.labels.italic':null,'chart.xaxis.labels.count':5,'chart.yaxis':true,'chart.yaxis.tickmarks.count':null,'chart.yaxis.labels':[],'chart.yaxis.labels.font':null,'chart.yaxis.labels.size':null,'chart.yaxis.labels.color':null,'chart.yaxis.labels.bold':null,'chart.yaxis.labels.italic':null,'chart.labels.above':false,'chart.labels.above.font':null,'chart.labels.above.size':null,'chart.labels.above.bold':null,'chart.labels.above.italic':null,'chart.labels.above.color':null,'chart.labels.above.units.pre':'','chart.labels.above.units.post':'','chart.labels.above.decimals':0,'chart.labels.above.formatter':null,'chart.text.bold':false,'chart.text.italic':false,'chart.text.size':12,'chart.text.color':'black','chart.text.font':'Arial, Verdana, sans-serif','chart.text.accessible':true,'chart.text.accessible.overflow':'visible','chart.text.accessible.pointerevents':false,'chart.title.left':null,'chart.title.left.font':null,'chart.title.left.size':null,'chart.title.left.bold':null,'chart.title.left.italic':null,'chart.title.left.color':null,'chart.title.right':null,'chart.title.right.font':null,'chart.title.right.size':null,'chart.title.right.bold':null,'chart.title.right.italic':null,'chart.title.right.color':null,'chart.margin.center':0,'chart.margin.center.auto':true,'chart.margin.left':25,'chart.margin.right':25,'chart.margin.top':25,'chart.margin.bottom':30,'chart.title':null,'chart.title.font':null,'chart.title.size':null,'chart.title.bold':null,'chart.title.italic':null,'chart.title.color':null,'chart.title.background':null,'chart.title.hpos':null,'chart.title.vpos':null,'chart.title.x':null,'chart.title.y':null,'chart.title.halign':null,'chart.title.valign':null,'chart.colors.stroke':'rgba(0,0,0,0)','chart.colors':['#afa','#faa','#aaf','#aff','#ffa','#faf','cyan','brown','gray','black','pink','#afa','#faa','#aaf','#aff','#ffa','#faf','cyan','brown','gray','black','pink'],'chart.colors.sequential':false,'chart.contextmenu':null,'chart.tooltips':null,'chart.tooltips.effect':'fade','chart.tooltips.css.class':'RGraph_tooltip','chart.tooltips.highlight':true,'chart.tooltips.event':'onclick','chart.highlight.stroke':'rgba(0,0,0,0)','chart.highlight.fill':'rgba(255,255,255,0.7)','chart.shadow':false,'chart.shadow.color':'#ccc','chart.shadow.offsetx':3,'chart.shadow.offsety':3,'chart.shadow.blur':3,'chart.annotatable':false,'chart.annotatable.color':'black','chart.axes':true,'chart.axes.color':'black','chart.axes.linewidth':1,'chart.resizable':false,'chart.resizable.handle.background':null,'chart.events.mousemove':null,'chart.events.click':null,'chart.linewidth':1,'chart.variant.threed.offsetx':10,'chart.variant.threed.offsety':5,'chart.variant.threed.angle':0.1,'chart.grouping':'grouped','chart.clearto':'rgba(0,0,0,0)'}
9
- this.properties['chart.yaxis.tickmarks.count']=this.left.length;var linear_data=RGraph.arrayLinearize(this.left,this.right);for(var i=0;i<linear_data.length;++i){this['$'+i]={};}
10
- if(!this.canvas.__rgraph_aa_translated__){this.context.translate(0.5,0.5);this.canvas.__rgraph_aa_translated__=true;}
11
- var RG=RGraph,ca=this.canvas,co=ca.getContext('2d'),prop=this.properties,pa2=RG.path2,win=window,doc=document,ma=Math
12
- if(RG.Effects&&typeof RG.Effects.decorate==='function'){RG.Effects.decorate(this);}
13
- this.set=this.Set=function(name)
14
- {var value=typeof arguments[1]==='undefined'?null:arguments[1];if(arguments.length===1&&typeof name==='object'){RG.parseObjectStyleConfig(this,name);return this;}
15
- if(name.substr(0,6)!='chart.'){name='chart.'+name;}
16
- while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
17
- prop[name]=value;return this;};this.get=this.Get=function(name)
18
- {if(name.substr(0,6)!='chart.'){name='chart.'+name;}
19
- while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
20
- return this.properties[name.toLowerCase()];};this.draw=this.Draw=function()
21
- {RG.fireCustomEvent(this,'onbeforedraw');if(!this.colorsParsed){this.parseColors();this.colorsParsed=true;}
22
- this.marginLeft=prop['chart.margin.left'];this.marginRight=prop['chart.margin.right'];this.marginTop=prop['chart.margin.top'];this.marginBottom=prop['chart.margin.bottom'];this.marginCenter=prop['chart.margin.center'];this.marginCenterAuto=prop['chart.margin.center.auto'];if(prop['chart.margin.center.auto']&&!prop['chart.margin.center']){prop['chart.margin.center']=this.getMarginCenter();}
23
- this.marginCenter=prop['chart.margin.center'];this.left=this.data[0];this.right=this.data[1];this.coords=[];this.coords2=[];this.coordsLeft=[];this.coordsRight=[];this.coords2Left=[];this.coords2Right=[];this.coordsText=[];if(prop['chart.variant']==='3d'){if(prop['chart.text.accessible']){}else{co.setTransform(1,prop['chart.variant.threed.angle'],0,1,0.5,0.5);}}
24
- this.axisWidth=(ca.width-prop['chart.margin.center']-this.marginLeft-this.marginRight)/2;this.axisHeight=ca.height-this.marginTop-this.marginBottom;this.sequentialFullIndex=0;this.getMax();this.drawBackgroundGrid();this.draw3DAxes();this.drawAxes();this.drawTicks();this.drawLeftBars();this.drawRightBars();this.drawLeftBars({shadow:false});this.drawRightBars({shadow:false});this.drawAxes();this.drawLabels();this.drawTitles();if(prop['chart.contextmenu']){RG.ShowContext(this);}
25
- if(prop['chart.resizable']){RG.AllowResizing(this);}
26
- RG.InstallEventListeners(this);if(this.firstDraw){this.firstDraw=false;RG.fireCustomEvent(this,'onfirstdraw');this.firstDrawFunc();}
27
- RG.FireCustomEvent(this,'ondraw');return this;};this.exec=function(func)
28
- {func(this);return this;};this.draw3DAxes=function()
29
- {if(prop['chart.variant']==='3d'){var offsetx=prop['chart.variant.threed.offsetx'],offsety=prop['chart.variant.threed.offsety'];co.lineWidth=prop['chart.axes.linewidth']+0.001;co.beginPath();co.strokeStyle=prop['chart.axes.color'];pa2(co,'b m % % l % % l % % l % % s #aaa f #ddd',this.marginLeft,ca.height-this.marginBottom,this.marginLeft+offsetx,ca.height-this.marginBottom-offsety,this.marginLeft+offsetx+this.axisWidth,ca.height-this.marginBottom-offsety,this.marginLeft+this.axisWidth,ca.height-this.marginBottom);this.draw3DLeftVerticalAxis();pa2(co,'b m % % l % % l % % l % % s #aaa f #ddd',this.marginLeft+this.marginCenter+this.axisWidth,ca.height-this.marginBottom,this.marginLeft+this.marginCenter+this.axisWidth+offsetx,ca.height-this.marginBottom-offsety,this.marginLeft+this.marginCenter+this.axisWidth+this.axisWidth+offsetx,ca.height-this.marginBottom-offsety,this.marginLeft+this.marginCenter+this.axisWidth+this.axisWidth,ca.height-this.marginBottom);pa2(co,'b m % % l % % l % % l % % s #aaa f #ddd',this.marginLeft+this.marginCenter+this.axisWidth,ca.height-this.marginBottom,this.marginLeft+this.marginCenter+this.axisWidth,ca.height-this.marginBottom-this.axisHeight,this.marginLeft+this.marginCenter+this.axisWidth+offsetx,ca.height-this.marginBottom-this.axisHeight-offsety,this.marginLeft+this.marginCenter+this.axisWidth+offsetx,ca.height-this.marginBottom-offsety);}}
30
- this.draw3DLeftVerticalAxis=function()
31
- {if(prop['chart.variant']==='3d'){var offsetx=prop['chart.variant.threed.offsetx'],offsety=prop['chart.variant.threed.offsety'];pa2(co,'b m % % l % % l % % l % % s #aaa f #ddd',this.marginLeft+this.axisWidth,this.marginTop,this.marginLeft+this.axisWidth+offsetx,this.marginTop-offsety,this.marginLeft+this.axisWidth+offsetx,ca.height-this.marginBottom-offsety,this.marginLeft+this.axisWidth,ca.height-this.marginBottom);}};this.drawAxes=this.DrawAxes=function()
32
- {co.lineWidth=prop['chart.axes.linewidth']+0.001;co.beginPath();co.strokeStyle=prop['chart.axes.color'];this.axisWidth=(ca.width-prop['chart.margin.center']-this.marginLeft-this.marginRight)/2;this.axisHeight=ca.height-this.marginTop-this.marginBottom;if(!prop['chart.axes']){return;}
33
- if(prop['chart.xaxis']){co.moveTo(this.marginLeft,ca.height-this.marginBottom);co.lineTo(this.marginLeft+this.axisWidth,ca.height-this.marginBottom);}
34
- if(prop['chart.yaxis']){co.moveTo(this.marginLeft+this.axisWidth,ca.height-this.marginBottom);co.lineTo(this.marginLeft+this.axisWidth,this.marginTop);}
35
- co.stroke();co.beginPath();var x=this.marginLeft+this.axisWidth+prop['chart.margin.center'];if(prop['chart.yaxis']){co.moveTo(x,this.marginTop);co.lineTo(x,ca.height-this.marginBottom);}
36
- if(prop['chart.xaxis']){co.moveTo(x,ca.height-this.marginBottom);co.lineTo(ca.width-this.marginRight,ca.height-this.marginBottom);}
37
- co.stroke();};this.drawTicks=this.DrawTicks=function()
38
- {co.lineWidth=prop['chart.axes.linewidth']+0.001;var numDataPoints=this.left.length;var barHeight=((ca.height-this.marginTop-this.marginBottom)-(this.left.length*(prop['chart.vmargin']*2)))/numDataPoints;this.barHeight=barHeight;if(!prop['chart.axes']){return;}
39
- if(prop['chart.yaxis']&&prop['chart.yaxis.tickmarks.count']>0){co.beginPath();for(var i=0;i<prop['chart.yaxis.tickmarks.count'];++i){var y=prop['chart.margin.top']+(((ca.height-this.marginTop-this.marginBottom)/prop['chart.yaxis.tickmarks.count'])*i);co.moveTo(this.marginLeft+this.axisWidth,y);co.lineTo(this.marginLeft+this.axisWidth+3,y);}
40
- co.stroke();co.beginPath();for(var i=0;i<prop['chart.yaxis.tickmarks.count'];++i){var y=prop['chart.margin.top']+(((ca.height-this.marginTop-this.marginBottom)/prop['chart.yaxis.tickmarks.count'])*i);co.moveTo(this.marginLeft+this.axisWidth+prop['chart.margin.center'],y);co.lineTo(this.marginLeft+this.axisWidth+prop['chart.margin.center']-3,y);}
41
- co.stroke();if(!prop['chart.xaxis']){pa2(co,'b m % % l % % s %',this.marginLeft+this.axisWidth,ca.height-this.marginBottom,this.marginLeft+this.axisWidth+4,(ca.height-this.marginBottom),co.strokeStyle);pa2(co,'b m % % l % % s %',this.marginLeft+this.axisWidth+prop['chart.margin.center'],ca.height-this.marginBottom,this.marginLeft+this.axisWidth+prop['chart.margin.center']-4,ca.height-this.marginBottom,co.strokeStyle);}}
42
- if(prop['chart.xaxis']&&prop['chart.xaxis.tickmarks.count']>0){var xInterval=this.axisWidth/prop['chart.xaxis.tickmarks.count'];if(typeof(prop['chart.xaxis.tickmarks.interval'])=='number'){xInterval=prop['chart.xaxis.tickmarks.interval'];}
43
- for(i=this.marginLeft;i<(this.marginLeft+this.axisWidth);i+=xInterval){co.beginPath();co.moveTo(i,ca.height-this.marginBottom);co.lineTo(i,(ca.height-this.marginBottom)+4);co.closePath();co.stroke();}
44
- var stoppingPoint=ca.width-this.marginRight;for(i=(this.marginLeft+this.axisWidth+prop['chart.margin.center']+xInterval);i<=stoppingPoint;i+=xInterval){co.beginPath();co.moveTo(i,ca.height-this.marginBottom);co.lineTo(i,(ca.height-this.marginBottom)+4);co.closePath();co.stroke();}
45
- if(!prop['chart.yaxis']){pa2(co,'b m % % l % % s %',this.marginLeft+this.axisWidth,ca.height-this.marginBottom,this.marginLeft+this.axisWidth,(ca.height-this.marginBottom)+4,co.strokeStyle);pa2(co,'b m % % l % % s %',this.marginLeft+this.axisWidth+prop['chart.margin.center'],ca.height-this.marginBottom,this.marginLeft+this.axisWidth+prop['chart.margin.center'],(ca.height-this.marginBottom)+4,co.strokeStyle);}}};this.getMax=this.GetMax=function()
46
- {var dec=prop['chart.xaxis.scale.decimals'];if(prop['chart.xaxis.scale.max']){var max=prop['chart.xaxis.scale.max'];var min=prop['chart.xaxis.scale.min'];this.scale2=RG.getScale2(this,{'scale.max':max,'scale.min':min,'scale.strict':true,'scale.thousand':prop['chart.xaxis.scale.thousand'],'scale.point':prop['chart.xaxis.scale.point'],'scale.decimals':prop['chart.xaxis.scale.decimals'],'scale.labels.count':prop['chart.xaxis.labels.count'],'scale.round':prop['chart.xaxis.scale.round'],'scale.units.pre':prop['chart.xaxis.scale.units.pre'],'scale.units.post':prop['chart.xaxis.scale.units.post']});this.max=this.scale2.max;this.min=this.scale2.min;}else{var max=1;for(var i=0;i<this.left.length;++i){if(typeof this.left[i]==='number'){max=ma.max(max,this.left[i]);}else if(RG.isNull(this.left[i])){}else{max=ma.max(max,prop['chart.grouping']==='stacked'?RG.arraySum(this.left[i]):RG.arrayMax(this.left[i]));}}
47
- for(var i=0;i<this.right.length;++i){if(typeof this.right[i]==='number'){max=ma.max(max,this.right[i]);}else if(RG.isNull(this.right[i])){}else{max=ma.max(max,prop['chart.grouping']==='stacked'?RG.arraySum(this.right[i]):RG.arrayMax(this.right[i]));}}
48
- this.scale2=RG.getScale2(this,{'scale.max':max,'scale.min':prop['chart.xsxis.scale.min'],'scale.thousand':prop['chart.xaxis.scale.thousand'],'scale.point':prop['chart.xaxis.scale.point'],'scale.decimals':prop['chart.xaxis.scale.decimals'],'scale.labels.count':prop['chart.xaxis.labels.count'],'scale.round':prop['chart.xaxis.scale.round'],'scale.units.pre':prop['chart.xaxis.scale.units.pre'],'scale.units.post':prop['chart.xaxis.scale.units.post']});this.max=this.scale2.max;this.min=this.scale2.min;}};this.drawLeftBars=this.DrawLeftBars=function()
49
- {var opt={};if(typeof arguments[0]==='object'){opt.shadow=arguments[0].shadow;}else{opt.shadow=true;}
50
- var offsetx=prop['chart.variant.threed.offsetx'],offsety=prop['chart.variant.threed.offsety'];co.strokeStyle=prop['chart.colors.stroke'];co.lineWidth=prop['chart.linewidth'];for(var i=0,sequentialColorIndex=0;i<this.left.length;++i){if(prop['chart.shadow']&&prop['chart.variant']!=='3d'&&opt.shadow){RG.setShadow({object:this,prefix:'chart.shadow'});}
51
- if(typeof this.left[i]==='number'){if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][sequentialColorIndex];}else{co.fillStyle=prop['chart.colors'][0];if(prop['chart.colors'].length===2){co.fillStyle=prop['chart.colors'][0];}}
52
- var width=(((this.left[i]-this.min)/(this.max-this.min))*this.axisWidth);var coords=[this.marginLeft+this.axisWidth-width,this.marginTop+(i*(this.axisHeight/this.left.length))+prop['chart.vmargin'],width,this.barHeight];if(this.left[i]!==null){co.strokeRect(coords[0],coords[1],coords[2],coords[3]);co.fillRect(coords[0],coords[1],coords[2],coords[3]);}
53
- if(prop['chart.variant']==='3d'&&this.left[i]!==null){if(prop['chart.shadow']&&opt.shadow){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];pa2(co,'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety+coords[3],coords[0]+offsetx,coords[1]-offsety+coords[3]);}
54
- if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][i];}else{co.fillStyle=prop['chart.colors'][0];}
55
- pa2(co,'b m % % l % % l % % l % % f %',coords[0],coords[1],coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+coords[2],coords[1]);pa2(co,'b m % % l % % l % % l % % f rgba(255,255,255,0.4)',coords[0],coords[1],coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+coords[2],coords[1]);}
56
- if(!opt.shadow){this.coords.push([coords[0],coords[1],coords[2],coords[3]]);this.coordsLeft.push([coords[0],coords[1],coords[2],coords[3]]);}
57
- sequentialColorIndex++;}else if(typeof this.left[i]==='object'&&prop['chart.grouping']==='stacked'){for(var j=0,accumulatedWidth=0;j<this.left[i].length;++j){if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][sequentialColorIndex];}else{co.fillStyle=prop['chart.colors'][j];}
58
- var value=this.left[i][j],min=this.min,max=this.max,margin=prop['chart.vmargin'],width=(((value-min)/(max-min))*this.axisWidth),sectionHeight=(this.axisHeight/this.left.length),height=(sectionHeight-(2*margin)),x=this.marginLeft+this.axisWidth-width-accumulatedWidth,y=this.marginTop+margin+(i*sectionHeight);accumulatedWidth+=width;if(this.left[i]!==null){co.strokeRect(x,y,width,height);co.fillRect(x,y,width,height);}
59
- if(prop['chart.variant']==='3d'&&this.left[i]!==null){if(prop['chart.shadow']&&opt.shadow){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];pa2(co,'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+offsetx+width,y-offsety+height,x+offsetx,y-offsety+height);}
60
- if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][sequentialColorIndex];}else{co.fillStyle=prop['chart.colors'][j];}
61
- pa2(co,'b m % % l % % l % % l % % f %',x,y,x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+width,y);pa2(co,'b m % % l % % l % % l % % f rgba(255,255,255,0.4)',x,y,x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+width,y);}
62
- if(!opt.shadow){this.coords.push([x,y,width,height]);this.coordsLeft.push([x,y,width,height]);if(!RG.isArray(this.coords2[i])){this.coords2[i]=[];}
63
- this.coords2[i].push([x,y,width,height]);if(!RG.isArray(this.coords2Left[i])){this.coords2Left[i]=[];}
64
- this.coords2Left[i].push([x,y,width,height]);}
65
- sequentialColorIndex++;}}else if(typeof this.left[i]==='object'&&!RG.isNull(this.left[i])){for(var j=0;j<this.left[i].length;++j){if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][sequentialColorIndex];}else{co.fillStyle=prop['chart.colors'][j];}
66
- var value=this.left[i][j],min=this.min,max=this.max,margin=prop['chart.vmargin'],marginGrouped=prop['chart.vmargin.grouped'],width=(((value-min)/(max-min))*this.axisWidth),sectionHeight=(this.axisHeight/this.left.length),height=(sectionHeight-(2*margin)-((this.left[i].length-1)*marginGrouped))/this.left[i].length,x=this.marginLeft+this.axisWidth-width,y=this.marginTop+margin+(i*sectionHeight)+(height*j)+(j*marginGrouped);if(this.left[i]!==null){co.strokeRect(x,y,width,height);co.fillRect(x,y,width,height);}
67
- if(prop['chart.variant']==='3d'&&this.left[i]!==null){if(prop['chart.shadow']&&opt.shadow){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];pa2(co,'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+offsetx+width,y-offsety+height,x+offsetx,y-offsety+height);}
68
- if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][sequentialColorIndex];}else{co.fillStyle=prop['chart.colors'][j];}
69
- pa2(co,'b m % % l % % l % % l % % f %',x,y,x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+width,y);pa2(co,'b m % % l % % l % % l % % f rgba(255,255,255,0.4)',x,y,x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+width,y);}
70
- if(!opt.shadow){this.coords.push([x,y,width,height]);this.coordsLeft.push([x,y,width,height]);if(!RG.isArray(this.coords2[i])){this.coords2[i]=[];}
71
- this.coords2[i].push([x,y,width,height]);if(!RG.isArray(this.coords2Left[i])){this.coords2Left[i]=[];}
72
- this.coords2Left[i].push([x,y,width,height]);}
73
- sequentialColorIndex++;}}
74
- this.draw3DLeftVerticalAxis();}
75
- RG.noShadow(this);co.lineWidth=1;};this.drawRightBars=this.DrawRightBars=function()
76
- {var opt={};if(typeof arguments[0]==='object'){opt.shadow=arguments[0].shadow;}else{opt.shadow=true;}
77
- var offsetx=prop['chart.variant.threed.offsetx'],offsety=prop['chart.variant.threed.offsety'];co.strokeStyle=prop['chart.colors.stroke'];co.lineWidth=prop['chart.linewidth'];if(prop['chart.shadow']&&prop['chart.variant']!=='3d'&&opt.shadow){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];}
78
- for(var i=0,sequentialColorIndex=RG.arrayLinearize(this.left).length;i<this.right.length;++i){if(typeof this.right[i]==='number'){if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][sequentialColorIndex];}else{co.fillStyle=prop['chart.colors'][0];if(prop['chart.colors'].length===2){co.fillStyle=prop['chart.colors'][1];}}
79
- var width=(((this.right[i]-this.min)/(this.max-this.min))*this.axisWidth);var coords=[this.marginLeft+this.axisWidth+prop['chart.margin.center'],prop['chart.vmargin']+(i*(this.axisHeight/this.right.length))+this.marginTop,width,this.barHeight];if(this.right[i]!==null){co.strokeRect(coords[0],coords[1],coords[2],coords[3]);co.fillRect(coords[0],coords[1],coords[2],coords[3]);}
80
- if(prop['chart.variant']==='3d'&&this.right[i]!==null){var color=co.fillStyle;if(prop['chart.shadow']&&opt.shadow){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];pa2(co,'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety+coords[3],coords[0]+offsetx,coords[1]-offsety+coords[3]);}
81
- pa2(co,'b m % % l % % l % % l % % f %',coords[0],coords[1],coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+coords[2],coords[1],color);pa2(co,'b m % % l % % l % % l % % f %',coords[0]+coords[2],coords[1],coords[0]+coords[2]+offsetx,coords[1]-offsety,coords[0]+coords[2]+offsetx,coords[1]-offsety+coords[3],coords[0]+coords[2],coords[1]+coords[3],color);pa2(co,'b m % % l % % l % % l % % f rgba(255,255,255,0.6)',coords[0],coords[1],coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+coords[2],coords[1]);pa2(co,'b m % % l % % l % % l % % f rgba(0,0,0,0.3)',coords[0]+coords[2],coords[1],coords[0]+coords[2]+offsetx,coords[1]-offsety,coords[0]+coords[2]+offsetx,coords[1]-offsety+coords[3],coords[0]+coords[2],coords[1]+coords[3]);}
82
- if(!opt.shadow){this.coords.push([coords[0],coords[1],coords[2],coords[3]]);this.coordsRight.push([coords[0],coords[1],coords[2],coords[3]]);}
83
- sequentialColorIndex++;}else if(typeof this.left==='object'&&prop['chart.grouping']==='stacked'){for(var j=0,accumulatedWidth=0;j<this.right[i].length;++j){if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][sequentialColorIndex];}else{co.fillStyle=prop['chart.colors'][j];}
84
- var value=this.right[i][j],min=this.min,max=this.max,margin=prop['chart.vmargin'],width=(((value-min)/(max-min))*this.axisWidth),sectionHeight=(this.axisHeight/this.right.length),height=(sectionHeight-(2*margin)),x=this.marginLeft+this.axisWidth+prop['chart.margin.center']+accumulatedWidth,y=this.marginTop+margin+(i*sectionHeight);accumulatedWidth+=width;if(this.right[i]!==null){co.strokeRect(x,y,width,height);co.fillRect(x,y,width,height);}
85
- if(prop['chart.variant']==='3d'&&this.right[i]!==null){var color=co.fillStyle;if(prop['chart.shadow']&&opt.shadow){RG.setShadow({object:this,prefix:'chart.shadow'});pa2(co,'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+offsetx+width,y-offsety+height,x+offsetx,y-offsety+height);}
86
- pa2(co,'b m % % l % % l % % l % % f %',x,y,x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+width,y,color);if(j===(this.right[i].length-1)){pa2(co,'b m % % l % % l % % l % % f %',x+width,y,x+width+offsetx,y-offsety,x+width+offsetx,y-offsety+height,x+width,y+height,color);pa2(co,'b m % % l % % l % % l % % f rgba(0,0,0,0.3)',x+width,y,x+width+offsetx,y-offsety,x+width+offsetx,y-offsety+height,x+width,y+height);}
87
- pa2(co,'b m % % l % % l % % l % % f rgba(255,255,255,0.6)',x,y,x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+width,y);}
88
- if(!opt.shadow){this.coords.push([x,y,width,height]);if(!RG.isArray(this.coords2[sequentialColorIndex])){this.coords2[sequentialColorIndex]=[];}
89
- this.coords2[sequentialColorIndex].push([x,y,width,height]);this.coordsRight.push([x,y,width,height]);if(!RG.isArray(this.coords2Right[i])){this.coords2Right[i]=[];}
90
- this.coords2Right[i].push([x,y,width,height]);}
91
- sequentialColorIndex++;}}else if(typeof this.right[i]==='object'){for(var j=0;j<this.right[i].length;++j){if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][sequentialColorIndex];}else{co.fillStyle=prop['chart.colors'][j];}
92
- var value=this.right[i][j],min=this.min,max=this.max,margin=prop['chart.vmargin'],marginGrouped=prop['chart.vmargin.grouped'],width=((value-min)/(max-min))*this.axisWidth,sectionHeight=(this.axisHeight/this.right.length),height=(sectionHeight-(2*margin)-((this.right[i].length-1)*marginGrouped))/this.right[i].length,x=this.marginLeft+this.axisWidth+prop['chart.margin.center'],y=this.marginTop+margin+(i*sectionHeight)+(height*j)+(j*marginGrouped);if(this.right[i]!==null){co.strokeRect(x,y,width,height);co.fillRect(x,y,width,height);}
93
- if(!opt.shadow){this.coords.push([x,y,width,height]);this.coordsRight.push([x,y,width,height]);if(!RG.isArray(this.coords2[this.left.length+i])){this.coords2[this.left.length+i]=[];}
94
- this.coords2[this.left.length+i].push([x,y,width,height]);if(!RG.isArray(this.coords2Right[i])){this.coords2Right[i]=[];}
95
- this.coords2Right[i].push([x,y,width,height]);}
96
- sequentialColorIndex++;if(prop['chart.variant']==='3d'&&this.right[i]!==null){var color=co.fillStyle;if(prop['chart.shadow']&&opt.shadow){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];pa2(co,'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+offsetx+width,y-offsety+height,x+offsetx,y-offsety+height);}
97
- pa2(co,'b m % % l % % l % % l % % f %',x,y,x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+width,y,color);pa2(co,'b m % % l % % l % % l % % f %',x+width,y,x+width+offsetx,y-offsety,x+width+offsetx,y-offsety+height,x+width,y+height,color);pa2(co,'b m % % l % % l % % l % % f rgba(255,255,255,0.6)',x,y,x+offsetx,y-offsety,x+offsetx+width,y-offsety,x+width,y);pa2(co,'b m % % l % % l % % l % % f rgba(0,0,0,0.3)',x+width,y,x+width+offsetx,y-offsety,x+width+offsetx,y-offsety+height,x+width,y+height);}}}}
98
- RG.noShadow(this);co.lineWidth=1;};this.drawLabels=this.DrawLabels=function()
99
- {var labels=prop['chart.yaxis.labels'],barAreaHeight=ca.height-this.marginTop-this.marginBottom
100
- var textConf=RG.getTextConf({object:this,prefix:'chart.yaxis.labels'});co.fillStyle=textConf.color;for(var i=0,len=labels.length;i<len;++i){RG.text2(this,{color:textConf.color,font:textConf.font,size:textConf.size,bold:textConf.bold,italic:textConf.italic,x:this.marginLeft+this.axisWidth+(prop['chart.margin.center']/2),y:this.marginTop+((barAreaHeight/labels.length)*(i))+((barAreaHeight/labels.length)/2),text:String(labels[i]?String(labels[i]):''),halign:'center',valign:'center',marker:false,tag:'labels'});}
101
- co.fillStyle=prop['chart.text.color'];if(prop['chart.xaxis.labels']){var grapharea=(ca.width-prop['chart.margin.center']-this.marginLeft-this.marginRight)/2;var textConf=RG.getTextConf({object:this,prefix:'chart.xaxis.labels'});for(var i=0;i<this.scale2.labels.length;++i){RG.text2(this,{font:textConf.font,size:textConf.size,bold:textConf.bold,italic:textConf.italic,color:textConf.color,x:this.marginLeft+((grapharea/this.scale2.labels.length)*i),y:ca.height-this.marginBottom+3,text:typeof prop['chart.xaxis.scale.formatter']==='function'?(prop['chart.xaxis.scale.formatter'])(this,this.scale2.values[this.scale2.values.length-i-1]):this.scale2.labels[this.scale2.labels.length-i-1],valign:'top',halign:'center',tag:'scale'});RG.text2(this,{font:textConf.font,size:textConf.size,bold:textConf.bold,italic:textConf.italic,color:textConf.color,x:this.marginLeft+grapharea+prop['chart.margin.center']+((grapharea/this.scale2.labels.length)*(i+1)),y:ca.height-this.marginBottom+3,text:this.scale2.labels[i],text:typeof prop['chart.xaxis.scale.formatter']==='function'?(prop['chart.xaxis.scale.formatter'])(this,this.scale2.values[i]):this.scale2.labels[i],valign:'top',halign:'center',tag:'scale'});}
102
- if(prop['chart.xaxis.scale.zerostart']){RG.text2(this,{font:textConf.font,size:textConf.size,bold:textConf.bold,italic:textConf.italic,color:textConf.color,x:this.marginLeft+this.axisWidth,y:ca.height-this.marginBottom+3,text:typeof prop['chart.xaxis.scale.formatter']==='function'?(prop['chart.xaxis.scale.formatter'])(this,0):RG.numberFormat({object:this,number:(0).toFixed(prop['chart.xaxis.scale.decimals']),unitspre:prop['chart.xaxis.scale.units.pre'],unitspost:prop['chart.xaxis.scale.units.post']}),valign:'top',halign:'center',tag:'scale'});RG.text2(this,{font:textConf.font,size:textConf.size,bold:textConf.bold,italic:textConf.italic,color:textConf.color,x:this.marginLeft+this.axisWidth+this.marginCenter,y:ca.height-this.marginBottom+3,text:typeof prop['chart.xaxis.scale.formatter']==='function'?(prop['chart.xaxis.scale.formatter'])(this,0):RG.numberFormat({object:this,number:(0).toFixed(prop['chart.xaxis.scale.decimals']),unitspre:prop['chart.xaxis.scale.units.pre'],unitspost:prop['chart.xaxis.scale.units.post']}),valign:'top',halign:'center',tag:'scale'});}}
103
- if(prop['chart.labels.above']){this.drawLabelsAbove();}};this.drawLabelsAbove=function()
104
- {var coordsLeft=this.coordsLeft,coordsRight=this.coordsRight;var textConf=RG.getTextConf({object:this,prefix:'chart.labels.above'});for(var i=0,seq=0;i<coordsLeft.length;++i,++seq){if(typeof this.left[i]=='number'){var coords=this.coords[seq];RG.text2(this,{font:textConf.font,size:textConf.size,bold:textConf.bold,italic:textConf.italic,color:textConf.color,x:coords[0]-5,y:coords[1]+(coords[3]/2),text:typeof prop['chart.labels.above.formatter']==='function'?prop['chart.labels.above.formatter'](this,this.left[i]):RG.numberFormat({object:this,number:this.left[i].toFixed(typeof prop['chart.labels.above.decimals']==='number'?prop['chart.labels.above.decimals']:0),unitspre:prop['chart.labels.above.units.pre'],unitspost:prop['chart.labels.above.units.post']}),valign:'center',halign:'right',tag:'labels.above'});}else if(typeof this.left[i]==='object'){for(var j=0;j<this.left[i].length;++j,++seq){if(prop['chart.grouping']==='stacked'&&j!==(this.left[i].length-1)){continue;}
105
- var coords=coordsLeft[seq];RG.text2(this,{font:textConf.font,size:textConf.size,bold:textConf.bold,italic:textConf.italic,color:textConf.color,x:coords[0]-5,y:coords[1]+(coords[3]/2),text:typeof prop['chart.labels.above.formatter']==='function'?prop['chart.labels.above.formatter'](this,this.left[i][j]):RG.numberFormat({object:this,number:RG.isNull(this.left[i][j])||isNaN(this.left[i][j])?'':(prop['chart.grouping']==='stacked'?RG.arraySum(this.left[i]):Number(this.left[i][j])).toFixed(typeof prop['chart.labels.above.decimals']==='number'?prop['chart.labels.above.decimals']:0),unitspre:prop['chart.labels.above.units.pre'],unitspost:prop['chart.labels.above.units.post']}),valign:'center',halign:'right',tag:'labels.above'});}
106
- seq--;}}
107
- for(i=0,seq=0;i<coordsRight.length;++i,++seq){if(typeof this.right[i]==='number'){var coords=coordsRight[seq];RG.text2(this,{font:textConf.font,size:textConf.size,bold:textConf.bold,italic:textConf.italic,color:textConf.color,x:coords[0]+coords[2]+5+(prop['chart.variant']==='3d'?10:0),y:coords[1]+(coords[3]/2)+(prop['chart.variant']==='3d'?-5:0),text:typeof prop['chart.labels.above.formatter']==='function'?prop['chart.labels.above.formatter'](this,this.right[i]):RG.numberFormat({object:this,number:this.right[i].toFixed(typeof prop['chart.labels.above.decimals']==='number'?prop['chart.labels.above.decimals']:0),unitspre:prop['chart.labels.above.units.pre'],unitspost:prop['chart.labels.above.units.post']}),valign:'center',halign:'left',tag:'labels.above'});}else if(typeof this.right[i]==='object'){for(var j=0;j<this.right[i].length;++j,++seq){if(prop['chart.grouping']==='stacked'&&j!==(this.right[i].length-1)){continue;}
108
- var coords=coordsRight[seq];RG.text2(this,{font:textConf.font,size:textConf.size,bold:textConf.bold,italic:textConf.italic,color:textConf.color,x:coords[0]+coords[2]+5+(prop['chart.variant']==='3d'?10:0),y:coords[1]+(coords[3]/2)+(prop['chart.variant']==='3d'?-5:0),text:typeof prop['chart.labels.above.formatter']==='function'?prop['chart.labels.above.formatter'](this,this.right[i][j]):RG.numberFormat({object:this,number:RG.isNull(this.right[i][j])||isNaN(this.right[i][j])?'':prop['chart.grouping']==='stacked'?RG.arraySum(this.right[i]).toFixed(prop['chart.labels.above.decimals']):Number(this.right[i][j]).toFixed(typeof prop['chart.labels.above.decimals']==='number'?prop['chart.labels.above.decimals']:0),unitspre:prop['chart.labels.above.units.pre'],unitspost:prop['chart.labels.above.units.post']}),valign:'center',halign:'left',tag:'labels.above'});}
109
- --seq;}}};this.drawTitles=this.DrawTitles=function()
110
- {var textConf=RG.getTextConf({object:this,prefix:'chart.title.left'});if(typeof prop['chart.title.left']==='string'){RG.text2(this,{font:textConf.font,size:textConf.size,bold:textConf.bold,italic:textConf.italic,color:textConf.color,x:this.marginLeft+5,y:this.marginTop-5,text:prop['chart.title.left'],halign:'left',valign:'bottom',tag:'title.left'});}
111
- var textConf=RG.getTextConf({object:this,prefix:'chart.title.right'});if(typeof prop['chart.title.right']==='string'){RG.text2(this,{font:textConf.font,size:textConf.size,bold:textConf.bold,italic:textConf.italic,color:textConf.color,x:ca.width-this.marginRight-5,y:this.marginTop-5,text:prop['chart.title.right'],halign:'right',valign:'bottom',tag:'title.right'});}
112
- if(typeof prop['chart.title']==='string'){RG.drawTitle(this,prop['chart.title'],this.marginTop,null,typeof prop['chart.title.size']==='number'?prop['chart.title.size']:null);}};this.getShape=this.getBar=function(e)
113
- {var canvas=this.canvas,context=this.context,mouseXY=RG.getMouseXY(e)
114
- for(var i=0;i<this.coords.length;i++){var mouseX=mouseXY[0],mouseY=mouseXY[1],left=this.coords[i][0],top=this.coords[i][1],width=this.coords[i][2],height=this.coords[i][3]
115
- if(prop['chart.variant']==='3d'){pa2(co,'b r % % % %',left,top,width,height);var over=co.isPointInPath(mouseX,mouseY);}else{var over=(mouseX>=left&&mouseX<=(left+width)&&mouseY>=top&&mouseY<=(top+height));}
116
- if(over){var tooltip=RG.parseTooltipText(prop['chart.tooltips'],i);return{0:this,1:left,2:top,3:width,4:height,5:i,object:this,x:left,y:top,width:width,height:height,index:i,tooltip:tooltip};}}
117
- return null;};this.highlight=this.Highlight=function(shape)
118
- {if(typeof prop['chart.highlight.style']==='function'){(prop['chart.highlight.style'])(shape);}else{RG.Highlight.Rect(this,shape);}};this.getValue=function(e)
119
- {var obj=e.target.__object__;var mouseXY=RG.getMouseXY(e);var mouseX=mouseXY[0];if(mouseX>this.marginLeft&&mouseX<((ca.width/2)-(prop['chart.margin.center']/2))){var value=(mouseX-prop['chart.margin.left'])/this.axisWidth;value=this.max-(value*this.max);}
120
- if(mouseX<(ca.width-this.marginRight)&&mouseX>((ca.width/2)+(prop['chart.margin.center']/2))){var value=(mouseX-prop['chart.margin.left']-this.axisWidth-prop['chart.margin.center'])/this.axisWidth;value=(value*this.max);}
121
- return value;};this.getObjectByXY=function(e)
122
- {var mouseXY=RG.getMouseXY(e);if(mouseXY[0]>prop['chart.margin.left']&&mouseXY[0]<(ca.width-prop['chart.margin.right'])&&mouseXY[1]>prop['chart.margin.top']&&mouseXY[1]<(ca.height-prop['chart.margin.bottom'])){return this;}};this.getXCoord=function(value)
123
- {if(value>this.max||value<0){return null;}
124
- var ret=[];var offset=((value/this.max)*this.axisWidth);ret[0]=(this.marginLeft+this.axisWidth)-offset;ret[1]=(ca.width-this.marginRight-this.axisWidth)+offset;return ret;};this.parseColors=function()
125
- {if(this.original_colors.length===0){this.original_colors['chart.colors']=RG.arrayClone(prop['chart.colors']);this.original_colors['chart.highlight.stroke']=RG.arrayClone(prop['chart.highlight.fill']);this.original_colors['chart.highlight.fill']=RG.arrayClone(prop['chart.highlight.fill']);this.original_colors['chart.axes.color']=RG.arrayClone(prop['chart.axes.color']);this.original_colors['chart.colors.stroke']=RG.arrayClone(prop['chart.colors.stroke']);}
126
- var props=this.properties;var colors=props['chart.colors'];for(var i=0;i<colors.length;++i){colors[i]=this.parseSingleColorForGradient(colors[i]);}
127
- props['chart.highlight.stroke']=this.parseSingleColorForGradient(props['chart.highlight.stroke']);props['chart.highlight.fill']=this.parseSingleColorForGradient(props['chart.highlight.fill']);props['chart.axes.color']=this.parseSingleColorForGradient(props['chart.axes.color']);props['chart.color.stroke']=this.parseSingleColorForGradient(props['chart.colors.stroke']);};this.reset=function()
128
- {};this.parseSingleColorForGradient=function(color)
129
- {if(!color||typeof(color)!='string'){return color;}
130
- if(color.match(/^gradient\((.*)\)$/i)){if(color.match(/^gradient\(({.*})\)$/i)){return RGraph.parseJSONGradient({object:this,def:RegExp.$1});}
131
- var parts=RegExp.$1.split(':');var grad=co.createLinearGradient(prop['chart.margin.left'],0,ca.width-prop['chart.margin.right'],0);var diff=1/(parts.length-1);grad.addColorStop(0,RG.trim(parts[0]));for(var j=1;j<parts.length;++j){grad.addColorStop(j*diff,RG.trim(parts[j]));}}
132
- return grad?grad:color;};this.on=function(type,func)
133
- {if(type.substr(0,2)!=='on'){type='on'+type;}
134
- if(typeof this[type]!=='function'){this[type]=func;}else{RG.addCustomEventListener(this,type,func);}
135
- return this;};this.drawBackgroundGrid=function()
136
- {if(prop['chart.background.grid']){var variant=prop['chart.variant'],color=prop['chart.background.grid.color'],numvlines=prop['chart.xaxis.labels.count'],numhlines=this.left.length,vlines=prop['chart.background.grid.vlines'],hlines=prop['chart.background.grid.hlines'],linewidth=prop['chart.background.grid.linewidth'];if(typeof prop['chart.background.grid.hlines.count']==='number'){numhlines=prop['chart.background.grid.hlines.count'];}
137
- if(typeof prop['chart.background.grid.vlines.count']==='number'){numvlines=prop['chart.background.grid.vlines.count'];}
138
- co.lineWidth=linewidth;if(variant=='3d'){co.save();co.translate(prop['chart.variant.threed.offsetx'],-1*prop['chart.variant.threed.offsety']);}
139
- if(vlines){for(var i=0;i<=numvlines;i+=1){pa2(co,'b m % % l % % s %',this.marginLeft+(this.axisWidth/numvlines)*i,this.marginTop,this.marginLeft+(this.axisWidth/numvlines)*i,this.marginTop+this.axisHeight,color);}}
140
- if(hlines){for(var i=0;i<=numhlines;i+=1){pa2(co,'b m % % l % % s %',this.marginLeft,this.marginTop+(this.axisHeight/numhlines)*i,this.marginLeft+this.axisWidth,this.marginTop+(this.axisHeight/numhlines)*i,color);}}
141
- if(vlines){for(var i=0;i<=numvlines;i+=1){pa2(co,'b m % % l % % s %',this.marginLeft+this.marginCenter+this.axisWidth+(this.axisWidth/numvlines)*i,this.marginTop,this.marginLeft+this.marginCenter+this.axisWidth+(this.axisWidth/numvlines)*i,this.marginTop+this.axisHeight,color);}}
142
- if(hlines){for(var i=0;i<=numhlines;i+=1){pa2(co,'b m % % l % % s %',this.marginLeft+this.axisWidth+this.marginCenter,this.marginTop+(this.axisHeight/numhlines)*i,this.marginLeft+this.axisWidth+this.marginCenter+this.axisWidth,this.marginTop+(this.axisHeight/numhlines)*i,color);}}
143
- if(variant=='3d'){co.restore();}}};this.firstDrawFunc=function()
144
- {};this.getGutterCenter=this.getMarginCenter=function()
145
- {var bold=typeof prop['chart.yaxis.labels.bold']==='boolean'?prop['chart.yaxis.labels.bold']:prop['chart.text.bold'],font=typeof prop['chart.yaxis.labels.font']==='string'?prop['chart.yaxis.labels.font']:prop['chart.text.font'],size=typeof prop['chart.yaxis.labels.size']==='number'?prop['chart.yaxis.labels.size']:prop['chart.text.size'];for(var i=0,len=0;i<prop['chart.yaxis.labels'].length;++i){len=ma.max(len,RG.measureText(prop['chart.yaxis.labels'][i],bold,font,size)[0]);}
146
- return len+15;};RG.Register(this);if(parseConfObjectForOptions){RG.parseObjectStyleConfig(this,conf.options);}
147
- this.grow=function()
148
- {var opt=arguments[0]||{},frames=opt.frames||30,frame=0,callback=arguments[1]||function(){},obj=this;var originalLeft=RG.arrayClone(this.left),originalRight=RG.arrayClone(this.right);if(RG.isNull(prop['chart.xaxis.scale.max'])){var xmax=0;this.getMax();this.Set('chart.xaxis.scale.max',this.scale2.max);}
149
- var iterator=function()
150
- {var easingMultiplier=RG.Effects.getEasingMultiplier(frames,frame);for(var i=0;i<obj.left.length;i+=1){if(typeof obj.left[i]==='number'){obj.left[i]=easingMultiplier*originalLeft[i];}else{for(var j=0;j<obj.left[i].length;++j){obj.left[i][j]=easingMultiplier*originalLeft[i][j];}}}
151
- for(var i=0;i<obj.right.length;i+=1){if(typeof obj.right[i]==='number'){obj.right[i]=easingMultiplier*originalRight[i];}else{for(var j=0;j<obj.right[i].length;++j){obj.right[i][j]=easingMultiplier*originalRight[i][j];}}}
152
- RG.redrawCanvas(obj.canvas);if(frame<frames){frame+=1;RG.Effects.updateCanvas(iterator);}else{callback(obj);}};iterator();return this;};this.wave=function()
153
- {var obj=this,opt=arguments[0]||{};opt.frames=opt.frames||120;opt.startFrames_left=[];opt.startFrames_right=[];opt.counters_left=[];opt.counters_right=[];var framesperbar=opt.frames/3,frame_left=-1,frame_right=-1,callback=arguments[1]||function(){},original_left=RG.arrayClone(obj.left),original_right=RG.arrayClone(obj.right);for(var i=0,len=obj.left.length;i<len;i+=1){opt.startFrames_left[i]=((opt.frames/3)/(obj.left.length-1))*i;opt.startFrames_right[i]=((opt.frames/3)/(obj.right.length-1))*i;opt.counters_left[i]=0;opt.counters_right[i]=0;}
154
- obj.draw();obj.set('chart.xaxis.scale.max',obj.scale2.max);RG.clear(obj.canvas);for(var i=0,len=obj.left.length;i<len;i+=1){if(typeof obj.left[i]==='number')obj.left[i]=0;if(typeof obj.right[i]==='number')obj.right[i]=0;}
155
- function iteratorLeft()
156
- {++frame_left;for(var i=0,len=obj.left.length;i<len;i+=1){if(frame_left>opt.startFrames_left[i]){var isNull=RG.isNull(obj.left[i]);if(typeof obj.left[i]==='number'){obj.left[i]=ma.min(ma.abs(original_left[i]),ma.abs(original_left[i]*((opt.counters_left[i]++)/framesperbar)));if(original_left[i]<0){obj.left[i]*=-1;}}else if(RG.isArray(obj.left[i])){for(var j=0;j<obj.left[i].length;++j){obj.left[i][j]=ma.min(ma.abs(original_left[i][j]),ma.abs(original_left[i][j]*((opt.counters_left[i]++)/framesperbar)));if(original_left[i][j]<0){obj.left[i][j]*=-1;}}}
157
- if(isNull){obj.left[i]=null;}}else{obj.left[i]=typeof obj.left[i]==='object'&&obj.left[i]?RG.arrayPad([],obj.left[i].length,0):(RG.isNull(obj.left[i])?null:0);}}
158
- if(frame_left<opt.frames){RG.redrawCanvas(obj.canvas);RG.Effects.updateCanvas(iteratorLeft);}}
159
- function iteratorRight()
160
- {++frame_right;for(var i=0,len=obj.right.length;i<len;i+=1){if(frame_right>opt.startFrames_right[i]){var isNull=RG.isNull(obj.right[i]);if(typeof obj.left[i]==='number'){obj.right[i]=ma.min(ma.abs(original_right[i]),ma.abs(original_right[i]*((opt.counters_right[i]++)/framesperbar)));if(original_right[i]<0){obj.right[i]*=-1;}
161
- if(isNull){obj.right[i]=null;}}else if(RG.isArray(obj.right[i])){for(var j=0;j<obj.right[i].length;++j){obj.right[i][j]=ma.min(ma.abs(original_right[i][j]),ma.abs(original_right[i][j]*((opt.counters_right[i]++)/framesperbar)));if(original_right[i][j]<0){obj.right[i][j]*=-1;}}}}else{obj.right[i]=typeof obj.right[i]==='object'&&obj.right[i]?RG.arrayPad([],obj.right[i].length,0):(RG.isNull(obj.right[i])?null:0);}}
162
- if(frame_right<opt.frames){RG.redrawCanvas(obj.canvas);RG.Effects.updateCanvas(iteratorRight);}else{callback(this);}}
163
- iteratorLeft();iteratorRight();return this;};};
13
+ RGraph = window.RGraph || {isrgraph:true,isRGraph: true,rgraph:true};
14
+
15
+ //
16
+ // The bipolar/age frequency constructor.
17
+ //
18
+ RGraph.Bipolar = function (conf)
19
+ {
20
+ var id = conf.id,
21
+ canvas = document.getElementById(id),
22
+ left = conf.left,
23
+ right = conf.right;
24
+
25
+ // Get the canvas and context objects
26
+ this.id = id;
27
+ this.canvas = canvas;
28
+ this.context = this.canvas.getContext('2d');
29
+ this.canvas.__object__ = this;
30
+ this.type = 'bipolar';
31
+ this.coords = [];
32
+ this.coords2 = [];
33
+ this.coordsLeft = [];
34
+ this.coordsRight = [];
35
+ this.coords2Left = [];
36
+ this.coords2Right = [];
37
+ this.max = 0;
38
+ this.isRGraph = true;
39
+ this.isrgraph = true;
40
+ this.rgraph = true;
41
+ this.uid = RGraph.createUID();
42
+ this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.createUID();
43
+ this.coordsText = [];
44
+ this.original_colors = [];
45
+ this.firstDraw = true; // After the first draw this will be false
46
+ this.stopAnimationRequested_left = false;// Used to control the animations
47
+ this.stopAnimationRequested_right = false;// Used to control the animations
48
+
49
+ // The left and right data respectively. Ensure that the data is an array
50
+ // of numbers
51
+ var data = [left, right];
52
+
53
+ // Convert strings to arrays
54
+ data[0] = RGraph.stringsToNumbers(data[0]);
55
+ data[1] = RGraph.stringsToNumbers(data[1]);
56
+
57
+
58
+ this.left = data[0];
59
+ this.right = data[1];
60
+ this.data = [data[0], data[1]];
61
+ this.data2 = [];
62
+
63
+ // Add all of the data to the data2 variable
64
+ for (var i=0;i<left.length; ++i) this.data2.push(left[i]);
65
+ for (var i=0;i<right.length; ++i) this.data2.push(right[i]);
66
+
67
+ this.properties =
68
+ {
69
+ backgroundGrid: true,
70
+ backgroundGridColor: '#ddd',
71
+ backgroundGridVlines: true,
72
+ backgroundGridHlines: true,
73
+ backgroundGridLinewidth: 1,
74
+ backgroundGridVlinesCount: null,
75
+ backgroundGridHlinesCount: null,
76
+
77
+ xaxis: true,
78
+ xaxisTickmarksCount: 5,
79
+ xaxisTickmarksInterval: null,
80
+ xaxisScaleUnitsPre: '',
81
+ xaxisScaleUnitsPost: '',
82
+ xaxisScaleMax: null,
83
+ xaxisScaleMin: 0,
84
+ xaxisScaleZerostart: true,
85
+ xaxisScaleDecimals: null,
86
+ xaxisScalePoint: '.',
87
+ xaxisScaleThousand: ',',
88
+ xaxisLabels: true,
89
+ xaxisLabelsFont: null,
90
+ xaxisLabelsSize: null,
91
+ xaxisLabelsColor: null,
92
+ xaxisLabelsBold: null,
93
+ xaxisLabelsItalic: null,
94
+ xaxisLabelsCount: 5,
95
+ xaxisLabelsOffsetx: 0,
96
+ xaxisLabelsOffsety: 0,
97
+
98
+ yaxis: true,
99
+ yaxisTickmarksCount: null,
100
+ yaxisLabels: [],
101
+ yaxisLabelsFont: null,
102
+ yaxisLabelsSize: null,
103
+ yaxisLabelsColor: null,
104
+ yaxisLabelsBold: null,
105
+ yaxisLabelsItalic: null,
106
+ yaxisLabelsOffsetx: 0,
107
+ yaxisLabelsOffsety: 0,
108
+ yaxisLabelsFormattedDecimals: 0,
109
+ yaxisLabelsFormattedPoint: '.',
110
+ yaxisLabelsFormattedThousand: ',',
111
+ yaxisLabelsFormattedUnitsPre: '',
112
+ yaxisLabelsFormattedUnitsPost: '',
113
+
114
+ labelsAbove: false,
115
+ labelsAboveFont: null,
116
+ labelsAboveSize: null,
117
+ labelsAboveBold: null,
118
+ labelsAboveItalic: null,
119
+ labelsAboveColor: null,
120
+ labelsAboveUnitsPre: '',
121
+ labelsAboveUnitsPost: '',
122
+ labelsAboveDecimals: 0,
123
+ labelsAboveFormatter: null,
124
+ labelsAboveOffsetx: 0,
125
+ labelsAboveOffsety: 0,
126
+
127
+ textBold: false,
128
+ textItalic: false,
129
+ textSize: 12,
130
+ textColor: 'black',
131
+ textFont: 'Arial, Verdana, sans-serif',
132
+ textAccessible: false,
133
+ textAccessibleOverflow: 'visible',
134
+ textAccessiblePointerevents:false,
135
+ text: null,
136
+
137
+ titleLeft: '',
138
+ titleLeftFont: null,
139
+ titleLeftSize: null,
140
+ titleLeftBold: null,
141
+ titleLeftItalic: null,
142
+ titleLeftColor: null,
143
+ titleLeftOffsetx: 0,
144
+ titleLeftOffsety: 0,
145
+
146
+ titleRight: '',
147
+ titleRightFont: null,
148
+ titleRightSize: null,
149
+ titleRightBold: null,
150
+ titleRightItalic: null,
151
+ titleRightColor: null,
152
+ titleOffsetx: 0,
153
+ titleOffsety: 0,
154
+ titleRightOffsetx: 0,
155
+ titleRightOffsety: 0,
156
+
157
+ title: '',
158
+ titleFont: null,
159
+ titleSize: null,
160
+ titleBold: null,
161
+ titleItalic: null,
162
+ titleColor: null,
163
+ titleX: null,
164
+ titleY: null,
165
+ titleHalign: null,
166
+ titleValign: null,
167
+ titleOffsetx: 0,
168
+ titleOffsety: 0,
169
+ titleSubtitle: '',
170
+ titleSubtitleSize: null,
171
+ titleSubtitleColor: '#aaa',
172
+ titleSubtitleFont: null,
173
+ titleSubtitleBold: null,
174
+ titleSubtitleItalic: null,
175
+ titleSubtitleOffsetx: 0,
176
+ titleSubtitleOffsety: 0,
177
+
178
+ marginCenter: 0,
179
+ marginCenterAuto: true,
180
+ marginLeft: 35,
181
+ marginRight: 35,
182
+ marginTop: 35,
183
+ marginBottom: 35,
184
+ marginInner: 5,
185
+ marginInnerGrouped: 3,
186
+
187
+
188
+ colorsStroke: 'rgba(0,0,0,0)',
189
+ colors: ['red','blue','yellow','#afa','#faa','#aaf','#aff','#ffa','#faf','cyan','brown','gray','black','pink','#afa','#faa','#aaf','#aff','#ffa','#faf','cyan','brown','gray','black','pink'],
190
+ //colors: ['#afa','#faa','#aaf','#aff','#ffa','#faf','cyan','brown','gray','black','pink','#afa','#faa','#aaf','#aff','#ffa','#faf','cyan','brown','gray','black','pink'],
191
+ colorsSequential: false,
192
+ colorsLeft: null,
193
+ colorsRight: null,
194
+
195
+ contextmenu: null,
196
+
197
+ tooltips: null,
198
+ tooltipsEffect: 'slide',
199
+ tooltipsCssClass: 'RGraph_tooltip',
200
+ tooltipsCss: null,
201
+ tooltipsHighlight: true,
202
+ tooltipsEvent: 'click',
203
+ tooltipsFormattedThousand: ',',
204
+ tooltipsFormattedPoint: '.',
205
+ tooltipsFormattedDecimals: 0,
206
+ tooltipsFormattedUnitsPre: '',
207
+ tooltipsFormattedUnitsPost: '',
208
+ tooltipsFormattedKeyColors: null,
209
+ tooltipsFormattedKeyColorsShape: 'square',
210
+ tooltipsFormattedKeyLabels: [],
211
+ tooltipsFormattedListType: 'ul',
212
+ tooltipsFormattedListItems: null,
213
+ tooltipsFormattedTableHeaders: null,
214
+ tooltipsFormattedTableData: null,
215
+ tooltipsPointer: true,
216
+ tooltipsPointerOffsetx: 0,
217
+ tooltipsPointerOffsety: 0,
218
+ tooltipsPositionStatic: true,
219
+ tooltipsHotspotIgnore: null,
220
+
221
+
222
+ key: null,
223
+ keyBackground: 'white',
224
+ keyPosition: 'graph',
225
+ keyShadow: false,
226
+ keyShadowColor: '#666',
227
+ keyShadowBlur: 3,
228
+ keyShadowOffsetx: 2,
229
+ keyShadowOffsety: 2,
230
+ keyPositionMarginBoxed: false,
231
+ keyPositionMarginHSpace: 0,
232
+ keyPositionX: null,
233
+ keyPositionY: null,
234
+ keyInteractive: false,
235
+ keyInteractiveHighlightChartStroke:'transparent',
236
+ keyInteractiveHighlightChartFill:'rgba(255,255,255,0.7)',
237
+ keyInteractiveHighlightLabel:'rgba(255,0,0,0.2)',
238
+ keyHalign: 'right',
239
+ keyColorShape: 'square',
240
+ keyRounded: true,
241
+ keyLinewidth: 1,
242
+ keyColors: null,
243
+ keyLabelsColor: null,
244
+ keyLabelsSize: null,
245
+ keyLabelsFont: null,
246
+ keyLabelsBold: null,
247
+ keyLabelsItalic: null,
248
+ keyLabelsOffsetx: 0,
249
+ keyLabelsOffsety: 0,
250
+ keyFormattedDecimals: 0,
251
+ keyFormattedPoint: '.',
252
+ keyFormattedThousand: ',',
253
+ keyFormattedUnitsPre: '',
254
+ keyFormattedUnitsPost: '',
255
+ keyFormattedValueSpecific: null,
256
+ keyFormattedItemsCount: null,
257
+
258
+ highlightStroke: 'rgba(0,0,0,0)',
259
+ highlightFill: 'rgba(255,255,255,0.7)',
260
+
261
+
262
+ shadow: false,
263
+ shadowColor: '#ccc',
264
+ shadowOffsetx: 3,
265
+ shadowOffsety: 3,
266
+ shadowOlur: 3,
267
+
268
+ annotatable: false,
269
+ annotatableColor: 'black',
270
+
271
+ axes: true,
272
+ axesColor: 'black',
273
+ axesLinewidth: 1,
274
+
275
+ resizable: false,
276
+ resizableHandleBackground: null,
277
+
278
+ linewidth: 1,
279
+
280
+ variantThreedOffsetx: 10,
281
+ variantThreedOffsety: 5,
282
+ variantThreedAngle: 0.1,
283
+
284
+ grouping: 'grouped',
285
+ clearto: 'rgba(0,0,0,0)',
286
+ leftVisible: true,
287
+ rightVisible: true
288
+ }
289
+
290
+ // Pad the arrays so they're the same size
291
+ //
292
+ // DON'T DO THIS NOW - 3/9/17
293
+ //while (this.left.length < this.right.length) this.left.push(null);
294
+ //while (this.left.length > this.right.length) this.right.push(null);
295
+
296
+ //
297
+ // Set the default for the number of Y tickmarks
298
+ //
299
+ this.properties.yaxisTickmarksCount = this.left.length;
300
+
301
+
302
+
303
+
304
+ //
305
+ // Create the dollar objects so that functions can be
306
+ // added to them
307
+ //
308
+ var linear_data = RGraph.arrayLinearize(this.left, this.right);
309
+
310
+ for (var i=0; i<linear_data.length; ++i) {
311
+ this['$' + i] = {};
312
+ } // Easy access to properties and the path function
313
+ var properties = this.properties;
314
+ this.path = RGraph.pathObjectFunction;
315
+
316
+
317
+
318
+ //
319
+ // "Decorate" the object with the generic effects if the effects library has been included
320
+ //
321
+ if (RGraph.Effects && typeof RGraph.Effects.decorate === 'function') {
322
+ RGraph.Effects.decorate(this);
323
+ }
324
+
325
+
326
+
327
+ // Add the responsive method. This method resides in the common file.
328
+ this.responsive = RGraph.responsive;
329
+
330
+
331
+
332
+
333
+
334
+
335
+
336
+
337
+ //
338
+ // The setter
339
+ //
340
+ // @param name string The name of the parameter to set
341
+ // @param value mixed The value of the paraneter
342
+ //
343
+ this.set = function (name)
344
+ {
345
+ var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
346
+
347
+ // the number of arguments is only one and it's an
348
+ // object - parse it for configuration data and return.
349
+ if (arguments.length === 1 && typeof arguments[0] === 'object') {
350
+ for (i in arguments[0]) {
351
+ if (typeof i === 'string') {
352
+ this.set(i, arguments[0][i]);
353
+ }
354
+ }
355
+
356
+ return this;
357
+ }
358
+
359
+ properties[name] = value;
360
+
361
+ return this;
362
+ };
363
+
364
+
365
+
366
+
367
+
368
+
369
+
370
+
371
+ //
372
+ // The getter
373
+ //
374
+ // @param name string The name of the parameter to get
375
+ //
376
+ this.get = function (name)
377
+ {
378
+ return this.properties[name];
379
+ };
380
+
381
+
382
+
383
+
384
+
385
+
386
+
387
+
388
+ //
389
+ // Draws the graph
390
+ //
391
+ this.draw = function ()
392
+ {
393
+ //
394
+ // Fire the onbeforedraw event
395
+ //
396
+ RGraph.fireCustomEvent(this, 'onbeforedraw');
397
+
398
+ // Translate half a pixel for antialiasing purposes - but only if it hasn't been
399
+ // done already
400
+ //
401
+ // MUST be the first thing done!
402
+ //
403
+ if (!this.canvas.__rgraph_aa_translated__) {
404
+ this.context.translate(0.5,0.5);
405
+
406
+ this.canvas.__rgraph_aa_translated__ = true;
407
+ }
408
+
409
+
410
+ //
411
+ // Parse the colors. This allows for simple gradient syntax
412
+ //
413
+ if (!this.colorsParsed) {
414
+ this.parseColors();
415
+
416
+ // Don't want to do this again
417
+ this.colorsParsed = true;
418
+ }
419
+
420
+
421
+
422
+ //
423
+ // Make the margins easy to access
424
+ //
425
+ this.marginLeft = properties.marginLeft;
426
+ this.marginRight = properties.marginRight;
427
+ this.marginTop = properties.marginTop;
428
+ this.marginBottom = properties.marginBottom;
429
+ this.marginCenter = properties.marginCenter;
430
+ this.marginCenterAuto = properties.marginCenterAuto;
431
+
432
+
433
+
434
+ if (properties.yaxisLabels && properties.yaxisLabels.length) {
435
+ //
436
+ // If the xaxisLabels option is a string then turn it
437
+ // into an array.
438
+ //
439
+ if (typeof properties.yaxisLabels === 'string') {
440
+ properties.yaxisLabels = RGraph.arrayPad({
441
+ array: [],
442
+ length: this.left.length,
443
+ value: properties.yaxisLabels
444
+ });
445
+ }
446
+
447
+ //
448
+ // Label substitution
449
+ //
450
+ for (var i=0; i<properties.yaxisLabels.length; ++i) {
451
+ properties.yaxisLabels[i] = RGraph.labelSubstitution({
452
+ object: this,
453
+ text: properties.yaxisLabels[i],
454
+ index: i,
455
+ value: this.left[i],
456
+ decimals: properties.yaxisLabelsFormattedDecimals || 0,
457
+ unitsPre: properties.yaxisLabelsFormattedUnitsPre || '',
458
+ unitsPost: properties.yaxisLabelsFormattedUnitsPost || '',
459
+ thousand: properties.yaxisLabelsFormattedThousand || ',',
460
+ point: properties.yaxisLabelsFormattedPoint || '.'
461
+ });
462
+ }
463
+ }
464
+
465
+
466
+
467
+ //
468
+ // Autosize the center margin to allow for big labels
469
+ //
470
+ if (properties.marginCenterAuto && !properties.marginCenter) {
471
+ properties.marginCenter = this.getMarginCenter();
472
+ }
473
+
474
+ this.marginCenter = properties.marginCenter;
475
+
476
+
477
+
478
+ // Reset the data to what was initially supplied
479
+ this.left = this.data[0];
480
+ this.right = this.data[1];
481
+
482
+
483
+ //
484
+ // Reset the coords array
485
+ //
486
+ this.coords = [];
487
+ this.coords2 = [];
488
+ this.coordsLeft = [];
489
+ this.coordsRight = [];
490
+ this.coords2Left = [];
491
+ this.coords2Right = [];
492
+
493
+
494
+
495
+ //
496
+ // Stop this growing uncontrollably
497
+ //
498
+ this.coordsText = [];
499
+
500
+
501
+ if (properties.variant === '3d') {
502
+ if (properties.textAccessible) {
503
+ // Nada
504
+ } else {
505
+ this.context.setTransform(1,properties.variantThreedAngle,0,1,0.5,0.5);
506
+ }
507
+ }
508
+
509
+
510
+
511
+ // Some necessary variables
512
+ this.axisWidth = (this.canvas.width - properties.marginCenter - this.marginLeft - this.marginRight) / 2;
513
+ this.axisHeight = this.canvas.height - this.marginTop - this.marginBottom;
514
+
515
+
516
+ // Reset the sequential index
517
+ this.sequentialFullIndex = 0;
518
+
519
+
520
+
521
+ this.getMax();
522
+ this.drawBackgroundGrid();
523
+ this.draw3DAxes();
524
+ this.drawAxes();
525
+ this.drawTicks();
526
+ this.drawLeftBars();
527
+ this.drawRightBars();
528
+
529
+ // Redraw the bars so that shadows on not on top
530
+ if (properties.leftVisible) this.drawLeftBars({shadow: false});
531
+ if (properties.rightVisible) this.drawRightBars({shadow: false});
532
+
533
+
534
+ this.drawAxes();
535
+
536
+ this.drawLabels();
537
+ this.drawTitles();
538
+
539
+ // Call this so that 3D charts are redrawn (the bar faces)
540
+ this.redraw3Dfaces();
541
+
542
+
543
+
544
+
545
+
546
+
547
+
548
+ // Draw the key if necessary
549
+ if (properties.key && properties.key.length) {
550
+ RGraph.drawKey(
551
+ this,
552
+ properties.key,
553
+ properties.colors
554
+ );
555
+ }
556
+
557
+
558
+
559
+
560
+ //
561
+ // Setup the context menu if required
562
+ //
563
+ if (properties.contextmenu) {
564
+ RGraph.showContext(this);
565
+ }
566
+
567
+
568
+
569
+
570
+ //
571
+ // Add custom text thats specified
572
+ //
573
+ RGraph.addCustomText(this);
574
+
575
+
576
+
577
+
578
+
579
+
580
+ //
581
+ // This installs the event listeners
582
+ //
583
+ RGraph.installEventListeners(this);
584
+
585
+
586
+ //
587
+ // Fire the onfirstdraw event
588
+ //
589
+ if (this.firstDraw) {
590
+ this.firstDraw = false;
591
+ RGraph.fireCustomEvent(this, 'onfirstdraw');
592
+ this.firstDrawFunc();
593
+ }
594
+
595
+
596
+ //
597
+ // Fire the RGraph draw event
598
+ //
599
+ RGraph.fireCustomEvent(this, 'ondraw');
600
+
601
+
602
+
603
+
604
+
605
+
606
+
607
+
608
+ //
609
+ // Install any inline responsive configuration. This
610
+ // should be last in the draw function - even after
611
+ // the draw events.
612
+ //
613
+ RGraph.installInlineResponsive(this);
614
+
615
+
616
+
617
+
618
+
619
+
620
+
621
+
622
+
623
+
624
+
625
+ return this;
626
+ };
627
+
628
+
629
+
630
+
631
+
632
+
633
+
634
+
635
+ //
636
+ // Used in chaining. Runs a function there and then - not waiting for
637
+ // the events to fire (eg the onbeforedraw event)
638
+ //
639
+ // @param function func The function to execute
640
+ //
641
+ this.exec = function (func)
642
+ {
643
+ func(this);
644
+
645
+ return this;
646
+ };
647
+
648
+
649
+
650
+
651
+
652
+
653
+
654
+
655
+ //
656
+ // Redraws 3D faces of bars so they look OK
657
+ //
658
+ this.redraw3Dfaces = function ()
659
+ {
660
+ //return;
661
+ // Redraw the faces of the bars so that if 3D mode is enabled the
662
+ // faces appear over the sides of other bars
663
+ if (properties.variant === '3d') {
664
+
665
+
666
+
667
+
668
+ // LEFT HAND SIDE BARS //
669
+
670
+
671
+
672
+ //
673
+ // If the colorsLeft option is set then change
674
+ // the colors option to that.
675
+ //
676
+ if (!RGraph.isNull(properties.colorsLeft)) {
677
+
678
+ // Save the initial colors value
679
+ properties.colorsInitial = properties.colors;
680
+
681
+ // Set the new value
682
+ properties.colors = properties.colorsLeft;
683
+ }
684
+
685
+
686
+
687
+ // A regular chart
688
+ if (this.coordsLeft.length > 0 && this.coords2Left.length === 0) {
689
+
690
+ for (var i=0; i<this.coordsLeft.length; ++i) {
691
+ this.path(
692
+ 'b r % % % % f %',
693
+ this.coordsLeft[i][0],
694
+ this.coordsLeft[i][1],
695
+ this.coordsLeft[i][2],
696
+ this.coordsLeft[i][3],
697
+ properties.colors[0]
698
+ );
699
+ }
700
+
701
+ // A grouped or stacked chart
702
+ } else {
703
+
704
+ for (var i=0; i<this.coords2Left.length; ++i) {
705
+ for (var j=0; j<this.coords2Left[i].length; ++j) {
706
+ this.path(
707
+ 'b r % % % % f %',
708
+ this.coords2Left[i][j][0],
709
+ this.coords2Left[i][j][1],
710
+ this.coords2Left[i][j][2],
711
+ this.coords2Left[i][j][3],
712
+ properties.colors[j]
713
+ );
714
+ }
715
+ }
716
+ }
717
+
718
+
719
+
720
+ // If the colorsLeft option is set then change
721
+ // the colors option back to what it was.
722
+ //
723
+ if (!RGraph.isNull(properties.colorsLeft)) {
724
+ properties.colors = properties.colorsInitial;
725
+ }
726
+
727
+
728
+
729
+
730
+ // RIGHT HAND SIDE BARS //
731
+
732
+
733
+
734
+ //
735
+ // If the colorsRight option is set then change
736
+ // the colors option to that.
737
+ //
738
+ if (!RGraph.isNull(properties.colorsRight)) {
739
+
740
+ // Save the initial colors value
741
+ properties.colorsInitial = properties.colors;
742
+
743
+ // Set the new value
744
+ properties.colors = properties.colorsRight;
745
+ }
746
+
747
+
748
+
749
+
750
+ var offsetx = properties.variantThreedOffsetx,
751
+ offsety = properties.variantThreedOffsety;
752
+
753
+ // A regular chart
754
+ if (this.coordsRight.length > 0 && this.coords2Right.length === 0) {
755
+
756
+ for (var i=0; i<this.coordsRight.length; ++i) {
757
+
758
+ var coords = this.coordsRight[i];
759
+
760
+ this.path(
761
+ 'b r % % % % f %',
762
+ coords[0], coords[1], coords[2], coords[3],
763
+ properties.colors[0]
764
+ );
765
+
766
+
767
+ // Draw the right hand side in the regular color
768
+ this.path(
769
+ 'b m % % l % % l % % l % % f %',
770
+ coords[0] + coords[2], coords[1],
771
+ coords[0] + coords[2] + offsetx, coords[1] - offsety,
772
+ coords[0] + coords[2] + offsetx, coords[1] - offsety + coords[3],
773
+ coords[0] + coords[2], coords[1] + coords[3],
774
+ properties.colors[0]
775
+ );
776
+
777
+
778
+ // Add the darker tint over thes top of the face to darken it
779
+ this.path(
780
+ 'b m % % l % % l % % l % % f %',
781
+ coords[0] + coords[2], coords[1],
782
+ coords[0] + coords[2] + offsetx, coords[1] - offsety,
783
+ coords[0] + coords[2] + offsetx, coords[1] - offsety + coords[3],
784
+ coords[0] + coords[2], coords[1] + coords[3],
785
+ 'rgba(0,0,0,0.3)'
786
+ );
787
+ }
788
+
789
+ // A grouped or stacked chart
790
+ } else {
791
+
792
+ for (var i=0; i<this.coords2Right.length; ++i) {
793
+ for (var j=(this.coords2Right[i].length - 1); j>=0; --j) {
794
+
795
+ var coords = this.coords2Right[i][j];
796
+
797
+ this.path(
798
+ 'b r % % % % f %',
799
+ coords[0], coords[1], coords[2], coords[3],
800
+ properties.colors[j]
801
+ );
802
+
803
+ // Draw the top side in the regular color
804
+ this.path(
805
+ 'b m % % l % % l % % l % % f %',
806
+ coords[0],coords[1],
807
+ coords[0] + offsetx, coords[1] - offsety,
808
+ coords[0] + coords[2] + offsetx, coords[1] - offsety,
809
+ coords[0] + coords[2], coords[1],
810
+ properties.colors[j]
811
+ );
812
+
813
+ // Draw the lighter tint over the top
814
+ this.path(
815
+ 'b m % % l % % l % % l % % f rgba(255,255,255,0.6)',
816
+ coords[0],coords[1],
817
+ coords[0] + offsetx, coords[1] - offsety,
818
+ coords[0] + coords[2] + offsetx, coords[1] - offsety,
819
+ coords[0] + coords[2], coords[1]
820
+ );
821
+
822
+
823
+ // Draw the right hand side in the regular color
824
+ this.path(
825
+ 'b m % % l % % l % % l % % f %',
826
+ coords[0] + coords[2],coords[1],
827
+ coords[0] + coords[2] + offsetx, coords[1] - offsety,
828
+ coords[0] + coords[2] + offsetx, coords[1] - offsety + coords[3],
829
+ coords[0] + coords[2], coords[1] + coords[3],
830
+ properties.colors[j]
831
+ );
832
+
833
+
834
+ // Add the darker tint over the top of the face to darken it
835
+ this.path(
836
+ 'b m % % l % % l % % l % % f %',
837
+ coords[0] + coords[2], coords[1],
838
+ coords[0] + coords[2] + offsetx, coords[1] - offsety,
839
+ coords[0] + coords[2] + offsetx, coords[1] - offsety + coords[3],
840
+ coords[0] + coords[2], coords[1] + coords[3],
841
+ 'rgba(0,0,0,0.3)'
842
+ );
843
+
844
+ }
845
+ }
846
+ }
847
+
848
+
849
+ // If the colorsRight option is set then change
850
+ // the colors option back to what it was.
851
+ //
852
+ if (!RGraph.isNull(properties.colorsRight)) {
853
+ properties.colors = properties.colorsInitial;
854
+ }
855
+
856
+ }
857
+ };
858
+
859
+
860
+
861
+
862
+
863
+
864
+
865
+
866
+ //
867
+ // Draws the axes
868
+ //
869
+ this.draw3DAxes = function ()
870
+ {
871
+ if (properties.variant === '3d') {
872
+ var offsetx = properties.variantThreedOffsetx,
873
+ offsety = properties.variantThreedOffsety;
874
+
875
+ // Set the linewidth
876
+ this.context.lineWidth = properties.axesLinewidth + 0.001;
877
+
878
+
879
+ // Draw the left set of axes
880
+ this.context.beginPath();
881
+ this.context.strokeStyle = properties.axesColor;
882
+
883
+ // Draw the horizontal 3d axis
884
+ // The left horizontal axis
885
+ this.path(
886
+ 'b m % % l % % l % % l % % s #aaa f #ddd',
887
+ this.marginLeft, this.canvas.height - this.marginBottom,
888
+ this.marginLeft + offsetx, this.canvas.height - this.marginBottom - offsety,
889
+ this.marginLeft + offsetx + this.axisWidth, this.canvas.height - this.marginBottom - offsety,
890
+ this.marginLeft + this.axisWidth, this.canvas.height - this.marginBottom
891
+ );
892
+
893
+ // The left vertical axis
894
+ this.draw3DLeftVerticalAxis();
895
+
896
+
897
+
898
+
899
+ // Draw the right horizontal axes
900
+ this.path(
901
+ 'b m % % l % % l % % l % % s #aaa f #ddd',
902
+ this.marginLeft + this.marginCenter + this.axisWidth, this.canvas.height - this.marginBottom,
903
+ this.marginLeft + this.marginCenter + this.axisWidth + offsetx, this.canvas.height - this.marginBottom - offsety,
904
+ this.marginLeft + this.marginCenter + this.axisWidth + this.axisWidth + offsetx, this.canvas.height - this.marginBottom - offsety,
905
+ this.marginLeft + this.marginCenter + this.axisWidth + this.axisWidth, this.canvas.height - this.marginBottom
906
+ );
907
+
908
+
909
+
910
+
911
+ // Draw the right vertical axes
912
+ this.path(
913
+ 'b m % % l % % l % % l % % s #aaa f #ddd',
914
+ this.marginLeft + this.marginCenter + this.axisWidth, this.canvas.height - this.marginBottom,
915
+ this.marginLeft + this.marginCenter + this.axisWidth, this.canvas.height - this.marginBottom - this.axisHeight,
916
+ this.marginLeft + this.marginCenter + this.axisWidth + offsetx, this.canvas.height - this.marginBottom - this.axisHeight - offsety,
917
+ this.marginLeft + this.marginCenter + this.axisWidth + offsetx, this.canvas.height - this.marginBottom - offsety
918
+ );
919
+ }
920
+ }
921
+
922
+
923
+
924
+
925
+
926
+
927
+
928
+
929
+ //
930
+ // Redraws the left vertical axis
931
+ //
932
+ this.draw3DLeftVerticalAxis = function ()
933
+ {
934
+ if (properties.variant === '3d') {
935
+ var offsetx = properties.variantThreedOffsetx,
936
+ offsety = properties.variantThreedOffsety;
937
+
938
+ // The left vertical axis
939
+ this.path(
940
+ 'b m % % l % % l % % l % % s #aaa f #ddd',
941
+ this.marginLeft + this.axisWidth, this.marginTop,
942
+ this.marginLeft + this.axisWidth + offsetx, this.marginTop - offsety,
943
+ this.marginLeft + this.axisWidth + offsetx, this.canvas.height - this.marginBottom - offsety,
944
+ this.marginLeft + this.axisWidth, this.canvas.height - this.marginBottom
945
+ );
946
+ }
947
+ };
948
+
949
+
950
+
951
+
952
+
953
+
954
+
955
+
956
+ //
957
+ // Draws the axes
958
+ //
959
+ this.drawAxes = function ()
960
+ {
961
+ // Set the linewidth
962
+ this.context.lineWidth = properties.axesLinewidth + 0.001;
963
+
964
+
965
+ // Draw the left set of axes
966
+ this.context.beginPath();
967
+ this.context.strokeStyle = properties.axesColor;
968
+
969
+ this.axisWidth = (this.canvas.width - properties.marginCenter - this.marginLeft - this.marginRight) / 2;
970
+ this.axisHeight = this.canvas.height - this.marginTop - this.marginBottom;
971
+
972
+
973
+ // This must be here so that the two above variables are calculated
974
+ if (!properties.axes) {
975
+ return;
976
+ }
977
+
978
+ if (properties.leftVisible) {
979
+ if (properties.xaxis) {
980
+ this.context.moveTo(
981
+ this.marginLeft,
982
+ this.canvas.height - this.marginBottom
983
+ );
984
+ this.context.lineTo(
985
+ this.marginLeft + this.axisWidth,
986
+ this.canvas.height - this.marginBottom
987
+ );
988
+ }
989
+
990
+ if (properties.yaxis) {
991
+ this.context.moveTo(this.marginLeft + this.axisWidth, this.canvas.height - this.marginBottom);
992
+ this.context.lineTo(this.marginLeft + this.axisWidth, this.marginTop);
993
+ }
994
+
995
+ this.context.stroke();
996
+ }
997
+
998
+
999
+ // Draw the right set of axes
1000
+ this.context.beginPath();
1001
+
1002
+ var x = this.marginLeft + this.axisWidth + properties.marginCenter;
1003
+
1004
+ if (properties.rightVisible) {
1005
+ if (properties.yaxis) {
1006
+ this.context.moveTo(x, this.marginTop);
1007
+ this.context.lineTo(x, this.canvas.height - this.marginBottom);
1008
+ }
1009
+
1010
+ if (properties.xaxis) {
1011
+ this.context.moveTo(x, this.canvas.height - this.marginBottom);
1012
+ this.context.lineTo(this.canvas.width - this.marginRight, this.canvas.height - this.marginBottom);
1013
+ }
1014
+
1015
+ this.context.stroke();
1016
+ }
1017
+ };
1018
+
1019
+
1020
+
1021
+
1022
+
1023
+
1024
+
1025
+
1026
+ //
1027
+ // Draws the tick marks on the axes
1028
+ //
1029
+ this.drawTicks = function ()
1030
+ {
1031
+ // Set the linewidth
1032
+ this.context.lineWidth = properties.axesLinewidth + 0.001;
1033
+
1034
+ var numDataPoints = this.left.length;
1035
+ var barHeight = ( (this.canvas.height - this.marginTop - this.marginBottom) - (this.left.length * (properties.marginInner * 2) )) / numDataPoints;
1036
+
1037
+ // Store this for later
1038
+ this.barHeight = barHeight;
1039
+
1040
+ // If no axes - no tickmarks
1041
+ if (!properties.axes) {
1042
+ return;
1043
+ }
1044
+
1045
+ // Draw the left Y tick marks
1046
+ if (properties.yaxis && properties.yaxisTickmarksCount > 0) {
1047
+
1048
+ if (properties.leftVisible) {
1049
+ this.context.beginPath();
1050
+ for (var i=0; i<properties.yaxisTickmarksCount; ++i) {
1051
+ var y = properties.marginTop + (((this.canvas.height - this.marginTop - this.marginBottom) / properties.yaxisTickmarksCount) * i);
1052
+ this.context.moveTo(this.marginLeft + this.axisWidth , y);
1053
+ this.context.lineTo(this.marginLeft + this.axisWidth + 3, y);
1054
+ }
1055
+ this.context.stroke();
1056
+ }
1057
+
1058
+
1059
+ if (properties.rightVisible) {
1060
+ //Draw the right axis Y tick marks
1061
+ this.context.beginPath();
1062
+ for (var i=0; i<properties.yaxisTickmarksCount; ++i) {
1063
+ var y = properties.marginTop + (((this.canvas.height - this.marginTop - this.marginBottom) / properties.yaxisTickmarksCount) * i);
1064
+ this.context.moveTo(this.marginLeft + this.axisWidth + properties.marginCenter, y);
1065
+ this.context.lineTo(this.marginLeft + this.axisWidth + properties.marginCenter - 3, y);
1066
+ }
1067
+ this.context.stroke();
1068
+ }
1069
+
1070
+
1071
+
1072
+
1073
+ // Draw an exra tick if the Y axis isn't being shown
1074
+ // on each of the sides
1075
+ if (!properties.xaxis) {
1076
+ if (properties.leftVisible) {
1077
+ this.path(
1078
+ 'b m % % l % % s %',
1079
+ this.marginLeft + this.axisWidth,this.canvas.height - this.marginBottom,
1080
+ this.marginLeft + this.axisWidth + 4,(this.canvas.height - this.marginBottom),
1081
+ this.context.strokeStyle
1082
+ );
1083
+ }
1084
+
1085
+ if (properties.rightVisible) {
1086
+ this.path(
1087
+ 'b m % % l % % s %',
1088
+ this.marginLeft + this.axisWidth + properties.marginCenter, this.canvas.height - this.marginBottom,
1089
+ this.marginLeft + this.axisWidth + properties.marginCenter - 4, this.canvas.height - this.marginBottom,
1090
+ this.context.strokeStyle
1091
+ );
1092
+ }
1093
+ }
1094
+ }
1095
+
1096
+
1097
+
1098
+ //
1099
+ // X tickmarks
1100
+ //
1101
+ if (properties.xaxis && properties.xaxisTickmarksCount > 0) {
1102
+ var xInterval = this.axisWidth / properties.xaxisTickmarksCount;
1103
+
1104
+ // Is xaxisTickmarksInterval specified ? If so, use that.
1105
+ if (typeof properties.xaxisTickmarksInterval == 'number') {
1106
+ xInterval = properties.xaxisTickmarksInterval;
1107
+ }
1108
+
1109
+
1110
+ // Draw the left sides X tick marks
1111
+ if (properties.leftVisible) {
1112
+ for (i=this.marginLeft; i<(this.marginLeft + this.axisWidth); i+=xInterval) {
1113
+ this.context.beginPath();
1114
+ this.context.moveTo(i, this.canvas.height - this.marginBottom);
1115
+ this.context.lineTo(i, (this.canvas.height - this.marginBottom) + 4);
1116
+ this.context.closePath();
1117
+
1118
+ this.context.stroke();
1119
+ }
1120
+ }
1121
+
1122
+ if (properties.rightVisible) {
1123
+ // Draw the right sides X tick marks
1124
+ var stoppingPoint = this.canvas.width - this.marginRight + 1;
1125
+
1126
+ for (i=(this.marginLeft + this.axisWidth + properties.marginCenter + xInterval); i<=stoppingPoint; i+=xInterval) {
1127
+ this.context.beginPath();
1128
+ this.context.moveTo(i, this.canvas.height - this.marginBottom);
1129
+ this.context.lineTo(i, (this.canvas.height - this.marginBottom) + 4);
1130
+ this.context.closePath();
1131
+ this.context.stroke();
1132
+ }
1133
+ }
1134
+
1135
+
1136
+ // Draw an exra tick if the Y axis isn't being shown
1137
+ // on each of the sides
1138
+ if (!properties.yaxis) {
1139
+
1140
+ if (properties.leftVisible) {
1141
+ this.path(
1142
+ 'b m % % l % % s %',
1143
+ this.marginLeft + this.axisWidth,this.canvas.height - this.marginBottom,
1144
+ this.marginLeft + this.axisWidth,(this.canvas.height - this.marginBottom) + 4,
1145
+ this.context.strokeStyle
1146
+ );
1147
+ }
1148
+
1149
+ if (properties.rightVisible) {
1150
+ this.path(
1151
+ 'b m % % l % % s %',
1152
+ this.marginLeft + this.axisWidth + properties.marginCenter,this.canvas.height - this.marginBottom,
1153
+ this.marginLeft + this.axisWidth + properties.marginCenter,(this.canvas.height - this.marginBottom) + 4,
1154
+ this.context.strokeStyle
1155
+ );
1156
+ }
1157
+ }
1158
+ }
1159
+ };
1160
+
1161
+
1162
+
1163
+
1164
+
1165
+
1166
+
1167
+
1168
+ //
1169
+ // Figures out the maximum value, or if defined, uses xaxisScaleMax
1170
+ //
1171
+ this.getMax = function()
1172
+ {
1173
+ var dec = properties.xaxisScaleDecimals;
1174
+
1175
+ // xaxisScaleMax defined
1176
+ if (properties.xaxisScaleMax) {
1177
+
1178
+ var max = properties.xaxisScaleMax;
1179
+ var min = properties.xaxisScaleMin;
1180
+
1181
+ this.scale2 = RGraph.getScale({object: this, options: {
1182
+ 'scale.max': max,
1183
+ 'scale.min': min,
1184
+ 'scale.strict': true,
1185
+ 'scale.thousand': properties.xaxisScaleThousand,
1186
+ 'scale.point': properties.xaxisScalePoint,
1187
+ 'scale.decimals': properties.xaxisScaleDecimals,
1188
+ 'scale.labels.count': properties.xaxisLabelsCount,
1189
+ 'scale.round': properties.xaxisScaleRound,
1190
+ 'scale.units.pre': properties.xaxisScaleUnitsPre,
1191
+ 'scale.units.post': properties.xaxisScaleUnitsPost
1192
+ }});
1193
+
1194
+ this.max = this.scale2.max;
1195
+ this.min = this.scale2.min;
1196
+
1197
+
1198
+ //
1199
+ // Generate the scale ourselves
1200
+ //
1201
+ } else {
1202
+
1203
+ var max = 1;
1204
+
1205
+ // Work out the max value for the left hand side
1206
+ for (var i=0; i<this.left.length; ++i) {
1207
+ if (typeof this.left[i] === 'number') {
1208
+ max = Math.max(max, this.left[i]);
1209
+ } else if (RGraph.isNull(this.left[i])) {
1210
+ // Nada
1211
+ } else {
1212
+ max = Math.max(max, properties.grouping === 'stacked' ? RGraph.arraySum(this.left[i]) : RGraph.arrayMax(this.left[i]));
1213
+ }
1214
+ }
1215
+
1216
+ // Work out the max value for the right hand side
1217
+ for (var i=0; i<this.right.length; ++i) {
1218
+ if (typeof this.right[i] === 'number') {
1219
+ max = Math.max(max, this.right[i]);
1220
+ } else if (RGraph.isNull(this.right[i])) {
1221
+ // Nada
1222
+ } else {
1223
+ max = Math.max(max, properties.grouping === 'stacked' ? RGraph.arraySum(this.right[i]) : RGraph.arrayMax(this.right[i]));
1224
+ }
1225
+ }
1226
+
1227
+ this.scale2 = RGraph.getScale({object: this, options: {
1228
+ 'scale.max': max,
1229
+ 'scale.min': properties.xaxisScaleMin,
1230
+ 'scale.thousand': properties.xaxisScaleThousand,
1231
+ 'scale.point': properties.xaxisScalePoint,
1232
+ 'scale.decimals': properties.xaxisScaleDecimals,
1233
+ 'scale.labels.count': properties.xaxisLabelsCount,
1234
+ 'scale.round': properties.xaxisScaleRound,
1235
+ 'scale.units.pre': properties.xaxisScaleUnitsPre,
1236
+ 'scale.units.post': properties.xaxisScaleUnitsPost
1237
+ }});
1238
+
1239
+
1240
+ this.max = this.scale2.max;
1241
+ this.min = this.scale2.min;
1242
+ }
1243
+
1244
+ // Don't need to return it as it is stored in this.max
1245
+ };
1246
+
1247
+
1248
+
1249
+
1250
+
1251
+
1252
+
1253
+
1254
+ // Function to draw the left hand bars
1255
+ this.drawLeftBars = function ()
1256
+ {
1257
+ // Allow the not-drawing of the left bars
1258
+ if (!properties.leftVisible) {
1259
+ return;
1260
+ }
1261
+
1262
+ var opt = {};
1263
+
1264
+ if (typeof arguments[0] === 'object') {
1265
+ opt.shadow = arguments[0].shadow;
1266
+ } else {
1267
+ opt.shadow = true;
1268
+ }
1269
+
1270
+ var offsetx = properties.variantThreedOffsetx,
1271
+ offsety = properties.variantThreedOffsety;
1272
+
1273
+ // Set the stroke colour
1274
+ this.context.strokeStyle = properties.colorsStroke;
1275
+
1276
+ // Set the linewidth
1277
+ this.context.lineWidth = properties.linewidth;
1278
+
1279
+
1280
+
1281
+
1282
+ //
1283
+ // If the colorsLeft option is set then change
1284
+ // the colors option to that.
1285
+ //
1286
+ if (!RGraph.isNull(properties.colorsLeft)) {
1287
+
1288
+ // Save the initial colors value
1289
+ properties.colorsInitial = properties.colors;
1290
+
1291
+ // Set the new value
1292
+ properties.colors = properties.colorsLeft;
1293
+ }
1294
+
1295
+
1296
+
1297
+
1298
+ for (var i=0,sequentialColorIndex=0; i<this.left.length; ++i) {
1299
+
1300
+ //
1301
+ // Turn on a shadow if requested
1302
+ //
1303
+ if (properties.shadow && properties.variant !== '3d' && opt.shadow) {
1304
+ RGraph.setShadow({
1305
+ object: this,
1306
+ prefix: 'shadow'
1307
+ });
1308
+ }
1309
+
1310
+
1311
+
1312
+ if (typeof this.left[i] === 'number') {
1313
+
1314
+ // If colorsSequential is specified - handle that
1315
+ // ** There's another instance of this further down **
1316
+ if (properties.colorsSequential) {
1317
+ this.context.fillStyle = properties.colors[sequentialColorIndex];
1318
+ } else {
1319
+ this.context.fillStyle = properties.colors[0];
1320
+
1321
+ // If there's only two colors then use them in the format of
1322
+ // one for each side. This facilitates easy coloring.
1323
+ //if (properties.colors.length === 2) {
1324
+ // this.context.fillStyle = properties.colors[0];
1325
+ //}
1326
+ }
1327
+
1328
+
1329
+
1330
+
1331
+ //
1332
+ // Work out the coordinates
1333
+ //
1334
+ var width = (( (this.left[i] - this.min) / (this.max - this.min)) * this.axisWidth);
1335
+
1336
+ var coords = [
1337
+ this.marginLeft + this.axisWidth - width,
1338
+ this.marginTop + (i * ( this.axisHeight / this.left.length)) + properties.marginInner,
1339
+ width,
1340
+ this.barHeight
1341
+ ];
1342
+
1343
+
1344
+ if (this.left[i] !== null) {
1345
+ this.context.strokeRect(
1346
+ coords[0],
1347
+ coords[1],
1348
+ coords[2],
1349
+ coords[3]
1350
+ );
1351
+
1352
+ this.context.fillRect(
1353
+ coords[0],
1354
+ coords[1],
1355
+ coords[2],
1356
+ coords[3]
1357
+ );
1358
+ }
1359
+
1360
+
1361
+ // Draw the 3D sides if required
1362
+ if (properties.variant === '3d' && this.left[i] !== null) {
1363
+
1364
+ // If the shadow is enabled draw the backface for
1365
+ // (that we don't actually see
1366
+ if (properties.shadow && opt.shadow) {
1367
+
1368
+ this.context.shadowColor = properties.shadowColor;
1369
+ this.context.shadowBlur = properties.shadowBlur;
1370
+ this.context.shadowOffsetX = properties.shadowOffsetx;
1371
+ this.context.shadowOffsetY = properties.shadowOffsety;
1372
+
1373
+
1374
+ this.path(
1375
+ 'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',
1376
+ coords[0] + offsetx, coords[1] - offsety,
1377
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
1378
+ coords[0] + offsetx + coords[2], coords[1] - offsety + coords[3],
1379
+ coords[0] + offsetx,coords[1] - offsety + coords[3]
1380
+ );
1381
+ }
1382
+
1383
+
1384
+
1385
+ // If colorsSequential is specified - handle that (again)
1386
+ //
1387
+ // ** There's another instance of this further up **
1388
+ if (properties.colorsSequential) {
1389
+ this.context.fillStyle = properties.colors[i];
1390
+
1391
+ } else {
1392
+ this.context.fillStyle = properties.colors[0];
1393
+ }
1394
+
1395
+ this.path(
1396
+ 'b m % % l % % l % % l % % f',
1397
+ coords[0],coords[1],
1398
+ coords[0] + offsetx, coords[1] - offsety,
1399
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
1400
+ coords[0] + coords[2], coords[1]
1401
+ );
1402
+
1403
+ this.path(
1404
+ 'b m % % l % % l % % l % % f rgba(255,255,255,0.4)',
1405
+ coords[0],coords[1],
1406
+ coords[0] + offsetx, coords[1] - offsety,
1407
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
1408
+ coords[0] + coords[2], coords[1]
1409
+ );
1410
+ }
1411
+
1412
+ // Only store coordinates if this isn't a shadow iteration
1413
+ if (!opt.shadow) {
1414
+
1415
+ // Add the coordinates to the coords array
1416
+ this.coords.push([
1417
+ coords[0],
1418
+ coords[1],
1419
+ coords[2],
1420
+ coords[3]
1421
+ ]);
1422
+
1423
+ this.coordsLeft.push([
1424
+ coords[0],
1425
+ coords[1],
1426
+ coords[2],
1427
+ coords[3]
1428
+ ]);
1429
+ }
1430
+
1431
+ sequentialColorIndex++;
1432
+
1433
+
1434
+
1435
+
1436
+
1437
+
1438
+
1439
+
1440
+ // A stacked Bipolar chart
1441
+ } else if (typeof this.left[i] === 'object' && properties.grouping === 'stacked') {
1442
+
1443
+ for (var j=0,accumulatedWidth=0; j<this.left[i].length; ++j) {
1444
+
1445
+ // If colorsSequential is specified - handle that
1446
+ // ** There's another instance of this further down **
1447
+ if (properties.colorsSequential) {
1448
+ this.context.fillStyle = properties.colors[sequentialColorIndex];
1449
+
1450
+ } else {
1451
+ this.context.fillStyle = properties.colors[j];
1452
+ }
1453
+
1454
+
1455
+
1456
+
1457
+ //
1458
+ // Work out the coordinates
1459
+ //
1460
+ var value = this.left[i][j],
1461
+ min = this.min,
1462
+ max = this.max,
1463
+ margin = properties.marginInner,
1464
+
1465
+ width = (( (value - min) / (max - min)) * this.axisWidth),
1466
+ sectionHeight = (this.axisHeight / this.left.length),
1467
+ height = (sectionHeight - (2 * margin)),
1468
+ x = this.marginLeft + this.axisWidth - width - accumulatedWidth,
1469
+ y = this.marginTop + margin + (i * sectionHeight);
1470
+
1471
+ accumulatedWidth += width;
1472
+
1473
+
1474
+ if (this.left[i] !== null) {
1475
+ this.context.strokeRect(x, y, width, height);
1476
+ this.context.fillRect(x, y, width, height);
1477
+ }
1478
+
1479
+
1480
+
1481
+
1482
+ // Draw the 3D sides if required =========================
1483
+ if (properties.variant === '3d' && this.left[i] !== null) {
1484
+
1485
+ // If the shadow is enabled draw the backface for
1486
+ // (that we don't actually see
1487
+ if (properties.shadow && opt.shadow) {
1488
+
1489
+ this.context.shadowColor = properties.shadowColor;
1490
+ this.context.shadowBlur = properties.shadowBlur;
1491
+ this.context.shadowOffsetX = properties.shadowOffsetx;
1492
+ this.context.shadowOffsetY = properties.shadowOffsety;
1493
+
1494
+
1495
+ this.path(
1496
+ 'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',
1497
+ x + offsetx, y - offsety,
1498
+ x + offsetx + width, y - offsety,
1499
+ x + offsetx + width, y - offsety + height,
1500
+ x + offsetx,y - offsety + height
1501
+ );
1502
+ }
1503
+
1504
+
1505
+
1506
+ // If colorsSequential is specified - handle that (again)
1507
+ //
1508
+ // ** There's another instance of this further up **
1509
+ if (properties.colorsSequential) {
1510
+ this.context.fillStyle = properties.colors[sequentialColorIndex];
1511
+ } else {
1512
+ this.context.fillStyle = properties.colors[j];
1513
+ }
1514
+
1515
+ // Top side
1516
+ this.path(
1517
+ 'b m % % l % % l % % l % % f',
1518
+ x,y,
1519
+ x + offsetx, y - offsety,
1520
+ x + offsetx + width, y - offsety,
1521
+ x + width, y
1522
+ );
1523
+
1524
+ // top side again (to lighten it)
1525
+ this.path(
1526
+ 'b m % % l % % l % % l % % f rgba(255,255,255,0.4)',
1527
+ x,y,
1528
+ x + offsetx, y - offsety,
1529
+ x + offsetx + width, y - offsety,
1530
+ x + width, y
1531
+ );
1532
+ }
1533
+ // ===== 3D ==========================================
1534
+
1535
+
1536
+
1537
+ // Only store coordinates if this isn't a shadow iteration
1538
+ if (!opt.shadow) {
1539
+
1540
+ //
1541
+ // Add the coordinates to the coords arrays
1542
+ //
1543
+
1544
+
1545
+
1546
+ // The .coords array
1547
+ this.coords.push([
1548
+ x,
1549
+ y,
1550
+ width,
1551
+ height
1552
+ ]);
1553
+
1554
+
1555
+
1556
+ // The .coordsLeft array
1557
+ this.coordsLeft.push([
1558
+ x,
1559
+ y,
1560
+ width,
1561
+ height
1562
+ ]);
1563
+
1564
+
1565
+
1566
+ // The .coords2 array
1567
+ if (!RGraph.isArray(this.coords2[i])) {
1568
+ this.coords2[i] = [];
1569
+ }
1570
+
1571
+ this.coords2[i].push([
1572
+ x,
1573
+ y,
1574
+ width,
1575
+ height
1576
+ ]);
1577
+
1578
+
1579
+
1580
+ // The .coords2Left array
1581
+ if (!RGraph.isArray(this.coords2Left[i])) {
1582
+ this.coords2Left[i] = [];
1583
+ }
1584
+
1585
+ this.coords2Left[i].push([
1586
+ x,
1587
+ y,
1588
+ width,
1589
+ height
1590
+ ]);
1591
+ }
1592
+
1593
+ sequentialColorIndex++;
1594
+ }
1595
+ // A grouped Bipolar chart - and this is also the default
1596
+ } else if (typeof this.left[i] === 'object' && !RGraph.isNull(this.left[i])) {
1597
+
1598
+ for (var j=0; j<this.left[i].length; ++j) {
1599
+
1600
+ // If colorsSequential is specified - handle that
1601
+ // ** There's another instance of this further down **
1602
+ if (properties.colorsSequential) {
1603
+ this.context.fillStyle = properties.colors[sequentialColorIndex];
1604
+
1605
+ } else {
1606
+ this.context.fillStyle = properties.colors[j];
1607
+ }
1608
+
1609
+
1610
+
1611
+
1612
+ //
1613
+ // Work out the coordinates
1614
+ //
1615
+ var value = this.left[i][j],
1616
+ min = this.min,
1617
+ max = this.max,
1618
+ margin = properties.marginInner,
1619
+ marginGrouped = properties.marginInnerGrouped,
1620
+
1621
+ width = (( (value - min) / (max - min)) * this.axisWidth),
1622
+ sectionHeight = (this.axisHeight / this.left.length),
1623
+ height = (sectionHeight - (2 * margin) - ( (this.left[i].length - 1) * marginGrouped)) / this.left[i].length,
1624
+ x = this.marginLeft + this.axisWidth - width,
1625
+ y = this.marginTop + margin + (i * sectionHeight) + (height * j) + (j * marginGrouped);
1626
+
1627
+
1628
+ if (this.left[i] !== null) {
1629
+ this.context.strokeRect(x, y, width, height);
1630
+ this.context.fillRect(x, y, width, height);
1631
+ }
1632
+
1633
+
1634
+
1635
+ // Draw the 3D sides if required
1636
+ if (properties.variant === '3d' && this.left[i] !== null) {
1637
+
1638
+ // If the shadow is enabled draw the backface for
1639
+ // (that we don't actually see
1640
+ if (properties.shadow && opt.shadow) {
1641
+
1642
+ this.context.shadowColor = properties.shadowColor;
1643
+ this.context.shadowBlur = properties.shadowBlur;
1644
+ this.context.shadowOffsetX = properties.shadowOffsetx;
1645
+ this.context.shadowOffsetY = properties.shadowOffsety;
1646
+
1647
+
1648
+ this.path(
1649
+ 'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',
1650
+ x + offsetx, y - offsety,
1651
+ x + offsetx + width, y - offsety,
1652
+ x + offsetx + width, y - offsety + height,
1653
+ x + offsetx,y - offsety + height
1654
+ );
1655
+ }
1656
+
1657
+
1658
+
1659
+ // If colorsSequential is specified - handle that (again)
1660
+ //
1661
+ // ** There's another instance of this further up **
1662
+ if (properties.colorsSequential) {
1663
+ this.context.fillStyle = properties.colors[sequentialColorIndex];
1664
+ } else {
1665
+ this.context.fillStyle = properties.colors[j];
1666
+ }
1667
+
1668
+ // Top side
1669
+ this.path(
1670
+ 'b m % % l % % l % % l % % f',
1671
+ x,y,
1672
+ x + offsetx, y - offsety,
1673
+ x + offsetx + width, y - offsety,
1674
+ x + width, y
1675
+ );
1676
+
1677
+ // top side again (to lighten it)
1678
+ this.path(
1679
+ 'b m % % l % % l % % l % % f rgba(255,255,255,0.4)',
1680
+ x,y,
1681
+ x + offsetx, y - offsety,
1682
+ x + offsetx + width, y - offsety,
1683
+ x + width, y
1684
+ );
1685
+ }
1686
+
1687
+
1688
+
1689
+ // Only store coordinates if this isn't a shadow iteration
1690
+ if (!opt.shadow) {
1691
+
1692
+
1693
+
1694
+ // Add the coordinates to the coords arrays
1695
+ this.coords.push([
1696
+ x,
1697
+ y,
1698
+ width,
1699
+ height
1700
+ ]);
1701
+
1702
+
1703
+
1704
+ this.coordsLeft.push([
1705
+ x,
1706
+ y,
1707
+ width,
1708
+ height
1709
+ ]);
1710
+
1711
+
1712
+
1713
+ if (!RGraph.isArray(this.coords2[i])) {
1714
+ this.coords2[i] = [];
1715
+ }
1716
+
1717
+ this.coords2[i].push([
1718
+ x,
1719
+ y,
1720
+ width,
1721
+ height
1722
+ ]);
1723
+
1724
+
1725
+
1726
+ if (!RGraph.isArray(this.coords2Left[i])) {
1727
+ this.coords2Left[i] = [];
1728
+ }
1729
+
1730
+ this.coords2Left[i].push([
1731
+ x,
1732
+ y,
1733
+ width,
1734
+ height
1735
+ ]);
1736
+ }
1737
+
1738
+ sequentialColorIndex++;
1739
+ }
1740
+ }
1741
+
1742
+
1743
+
1744
+ // Now draw the left vertical axis again so that it appears
1745
+ // over the bars
1746
+ this.draw3DLeftVerticalAxis();
1747
+ }
1748
+
1749
+ //
1750
+ // If the colorsLeft option is set then change
1751
+ // the colors option back to what it was.
1752
+ //
1753
+ if (!RGraph.isNull(properties.colorsLeft)) {
1754
+ properties.colors = properties.colorsInitial;
1755
+ }
1756
+
1757
+ //
1758
+ // Turn off any shadow
1759
+ //
1760
+ RGraph.noShadow(this);
1761
+
1762
+ // Reset the linewidth
1763
+ this.context.lineWidth = 1;
1764
+ };
1765
+
1766
+
1767
+
1768
+
1769
+
1770
+
1771
+
1772
+
1773
+ //
1774
+ // Function to draw the right hand bars
1775
+ //
1776
+ this.drawRightBars = function ()
1777
+ {
1778
+ // Allow the not-drawing of the right bars
1779
+ if (!properties.rightVisible) {
1780
+ return;
1781
+ }
1782
+
1783
+ var opt = {};
1784
+
1785
+ if (typeof arguments[0] === 'object') {
1786
+ opt.shadow = arguments[0].shadow;
1787
+ } else {
1788
+ opt.shadow = true;
1789
+ }
1790
+
1791
+ var offsetx = properties.variantThreedOffsetx,
1792
+ offsety = properties.variantThreedOffsety;
1793
+
1794
+
1795
+
1796
+
1797
+ // Set the stroke colour
1798
+ this.context.strokeStyle = properties.colorsStroke;
1799
+
1800
+ // Set the linewidth
1801
+ this.context.lineWidth = properties.linewidth;
1802
+
1803
+ //
1804
+ // Turn on a shadow if requested
1805
+ //
1806
+ if (properties.shadow && properties.variant !== '3d' && opt.shadow) {
1807
+ this.context.shadowColor = properties.shadowColor;
1808
+ this.context.shadowBlur = properties.shadowBlur;
1809
+ this.context.shadowOffsetX = properties.shadowOffsetx;
1810
+ this.context.shadowOffsetY = properties.shadowOffsety;
1811
+ }
1812
+
1813
+
1814
+ //
1815
+ // If the colorsLeft option is set then change
1816
+ // the colors option to that.
1817
+ //
1818
+ if (!RGraph.isNull(properties.colorsRight)) {
1819
+
1820
+ // Save the initial colors value
1821
+ properties.colorsInitial = properties.colors;
1822
+
1823
+ // Set the new value
1824
+ properties.colors = properties.colorsRight;
1825
+ }
1826
+
1827
+
1828
+
1829
+
1830
+ for (var i=0,sequentialColorIndex=RGraph.arrayLinearize(this.left).length; i<this.right.length; ++i) {
1831
+
1832
+ if (typeof this.right[i] === 'number') {
1833
+
1834
+ // If colorsSequential is specified - handle that
1835
+ if (properties.colorsSequential) {
1836
+ this.context.fillStyle = properties.colors[sequentialColorIndex];
1837
+ } else {
1838
+ this.context.fillStyle = properties.colors[0];
1839
+ }
1840
+
1841
+
1842
+
1843
+ var width = (((this.right[i] - this.min) / (this.max - this.min)) * this.axisWidth);
1844
+
1845
+ var coords = [
1846
+ this.marginLeft + this.axisWidth + properties.marginCenter,
1847
+ properties.marginInner + (i * (this.axisHeight / this.right.length)) + this.marginTop,
1848
+ width,
1849
+ this.barHeight
1850
+ ];
1851
+
1852
+
1853
+ if (this.right[i] !== null) {
1854
+ this.context.strokeRect(
1855
+ coords[0],
1856
+ coords[1],
1857
+ coords[2],
1858
+ coords[3]
1859
+ );
1860
+ this.context.fillRect(
1861
+ coords[0],
1862
+ coords[1],
1863
+ coords[2],
1864
+ coords[3]
1865
+ );
1866
+ }
1867
+
1868
+
1869
+
1870
+
1871
+
1872
+
1873
+
1874
+
1875
+
1876
+
1877
+
1878
+
1879
+
1880
+ // Draw the 3D sides if required
1881
+ if (properties.variant === '3d' && this.right[i] !== null) {
1882
+
1883
+
1884
+ var color = this.context.fillStyle;
1885
+
1886
+
1887
+ // If the shadow is enabled draw the backface for
1888
+ // (that we don't actually see
1889
+ if (properties.shadow && opt.shadow) {
1890
+
1891
+ this.context.shadowColor = properties.shadowColor;
1892
+ this.context.shadowBlur = properties.shadowBlur;
1893
+ this.context.shadowOffsetX = properties.shadowOffsetx;
1894
+ this.context.shadowOffsetY = properties.shadowOffsety;
1895
+
1896
+ this.path(
1897
+ 'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',
1898
+ coords[0] + offsetx, coords[1] - offsety,
1899
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
1900
+ coords[0] + offsetx + coords[2], coords[1] - offsety + coords[3],
1901
+ coords[0] + offsetx,coords[1] - offsety + coords[3]
1902
+ );
1903
+ }
1904
+
1905
+ // Draw the top
1906
+ this.path(
1907
+ 'b m % % l % % l % % l % % f %',
1908
+ coords[0],coords[1],
1909
+ coords[0] + offsetx, coords[1] - offsety,
1910
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
1911
+ coords[0] + coords[2], coords[1],
1912
+ color
1913
+ );
1914
+
1915
+
1916
+ // Draw the right hand side
1917
+ this.path(
1918
+ 'b m % % l % % l % % l % % f %',
1919
+ coords[0] + coords[2],coords[1],
1920
+ coords[0] + coords[2] + offsetx, coords[1] - offsety,
1921
+ coords[0] + coords[2] + offsetx, coords[1] - offsety + coords[3],
1922
+ coords[0] + coords[2],coords[1] + coords[3],
1923
+ color
1924
+ );
1925
+
1926
+ // Draw the LIGHTER top
1927
+ this.path(
1928
+ 'b m % % l % % l % % l % % f rgba(255,255,255,0.6)',
1929
+ coords[0],coords[1],
1930
+ coords[0] + offsetx, coords[1] - offsety,
1931
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
1932
+ coords[0] + coords[2], coords[1]
1933
+ );
1934
+
1935
+
1936
+ // Draw the DARKER right hand side
1937
+ this.path(
1938
+ 'b m % % l % % l % % l % % f rgba(0,0,0,0.3)',
1939
+ coords[0] + coords[2],coords[1],
1940
+ coords[0] + coords[2] + offsetx, coords[1] - offsety,
1941
+ coords[0] + coords[2] + offsetx, coords[1] - offsety + coords[3],
1942
+ coords[0] + coords[2],coords[1] + coords[3]
1943
+ );
1944
+ }
1945
+
1946
+
1947
+
1948
+
1949
+
1950
+
1951
+
1952
+
1953
+
1954
+
1955
+
1956
+
1957
+ // Only store coordinates if this isn't a shadow iteration
1958
+ if (!opt.shadow) {
1959
+
1960
+ //
1961
+ // Add the coordinates to the coords array
1962
+ //
1963
+
1964
+ // The .coords array
1965
+ this.coords.push([
1966
+ coords[0],
1967
+ coords[1],
1968
+ coords[2],
1969
+ coords[3]
1970
+ ]);
1971
+
1972
+ // The .coordsRight array
1973
+ this.coordsRight.push([
1974
+ coords[0],
1975
+ coords[1],
1976
+ coords[2],
1977
+ coords[3]
1978
+ ]);
1979
+ }
1980
+
1981
+ // Does this need to be here?
1982
+ sequentialColorIndex++;
1983
+
1984
+
1985
+
1986
+
1987
+
1988
+
1989
+
1990
+ // A stacked Bipolar chart
1991
+ } else if (typeof this.left === 'object' && properties.grouping === 'stacked') {
1992
+
1993
+ for (var j=0,accumulatedWidth=0; j<this.right[i].length; ++j) {
1994
+
1995
+ // If colorsSequential is specified - handle that
1996
+ // ** There's another instance of this further down **
1997
+ if (properties.colorsSequential) {
1998
+ this.context.fillStyle = properties.colors[sequentialColorIndex];
1999
+
2000
+ } else {
2001
+ this.context.fillStyle = properties.colors[j];
2002
+ }
2003
+
2004
+
2005
+
2006
+
2007
+ //
2008
+ // Work out the coordinates
2009
+ //
2010
+ var value = this.right[i][j],
2011
+ min = this.min,
2012
+ max = this.max,
2013
+ margin = properties.marginInner,
2014
+
2015
+ width = (( (value - min) / (max - min)) * this.axisWidth),
2016
+ sectionHeight = (this.axisHeight / this.right.length),
2017
+ height = (sectionHeight - (2 * margin)),
2018
+ x = this.marginLeft + this.axisWidth + properties.marginCenter + accumulatedWidth,
2019
+ y = this.marginTop + margin + (i * sectionHeight);
2020
+
2021
+ accumulatedWidth += width;
2022
+
2023
+
2024
+ if (this.right[i] !== null) {
2025
+ this.context.strokeRect(x, y, width, height);
2026
+ this.context.fillRect(x, y, width, height);
2027
+ }
2028
+
2029
+
2030
+
2031
+ // Draw the 3D sides if required
2032
+ if (properties.variant === '3d' && this.right[i] !== null) {
2033
+
2034
+ var color = this.context.fillStyle;
2035
+
2036
+
2037
+ // If the shadow is enabled draw the backface for
2038
+ // (that we don't actually see
2039
+ if (properties.shadow && opt.shadow) {
2040
+
2041
+ RGraph.setShadow({
2042
+ object: this,
2043
+ prefix: 'shadow'
2044
+ });
2045
+
2046
+ this.path(
2047
+ 'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',
2048
+ x + offsetx, y - offsety,
2049
+ x + offsetx + width, y - offsety,
2050
+ x + offsetx + width, y - offsety + height,
2051
+ x + offsetx, y - offsety + height
2052
+ );
2053
+ }
2054
+
2055
+ // Draw the top
2056
+ this.path(
2057
+ 'b m % % l % % l % % l % % f %',
2058
+ x, y,
2059
+ x + offsetx, y - offsety,
2060
+ x + offsetx + width, y - offsety,
2061
+ x + width, y,
2062
+ color
2063
+ );
2064
+
2065
+
2066
+ // Draw the right hand side - but only
2067
+ // if this the most right hand side segment
2068
+ if (j === (this.right[i].length - 1)) {
2069
+ this.path(
2070
+ 'b m % % l % % l % % l % % f %',
2071
+ x + width,y,
2072
+ x + width + offsetx, y - offsety,
2073
+ x + width + offsetx, y - offsety + height,
2074
+ x + width,y + height,
2075
+ color
2076
+ );
2077
+
2078
+ // Draw the DARKER right hand side
2079
+ this.path(
2080
+ 'b m % % l % % l % % l % % f rgba(0,0,0,0.3)',
2081
+ x + width,y,
2082
+ x + width + offsetx, y - offsety,
2083
+ x + width + offsetx, y - offsety + height,
2084
+ x + width,y + height
2085
+ );
2086
+ }
2087
+
2088
+ // Draw the LIGHTER top
2089
+ this.path(
2090
+ 'b m % % l % % l % % l % % f rgba(255,255,255,0.6)',
2091
+ x,y,
2092
+ x + offsetx, y - offsety,
2093
+ x + offsetx + width, y - offsety,
2094
+ x + width, y
2095
+ );
2096
+ }
2097
+
2098
+
2099
+ // Only store coordinates if this isn't a shadow iteration
2100
+ if (!opt.shadow) {
2101
+
2102
+ // Add the coordinates to the coords arrays
2103
+ this.coords.push([
2104
+ x,
2105
+ y,
2106
+ width,
2107
+ height
2108
+ ]);
2109
+
2110
+
2111
+
2112
+ // The .coords2 array
2113
+ if (!RGraph.isArray(this.coords2[sequentialColorIndex])) {
2114
+ this.coords2[sequentialColorIndex] = [];
2115
+ }
2116
+
2117
+ this.coords2[sequentialColorIndex].push([
2118
+ x,
2119
+ y,
2120
+ width,
2121
+ height
2122
+ ]);
2123
+
2124
+
2125
+
2126
+ this.coordsRight.push([
2127
+ x,
2128
+ y,
2129
+ width,
2130
+ height
2131
+ ]);
2132
+
2133
+
2134
+
2135
+ // The .coords2Right array
2136
+ if (!RGraph.isArray(this.coords2Right[i])) {
2137
+ this.coords2Right[i] = [];
2138
+ }
2139
+
2140
+ this.coords2Right[i].push([
2141
+ x,
2142
+ y,
2143
+ width,
2144
+ height
2145
+ ]);
2146
+ }
2147
+
2148
+ sequentialColorIndex++;
2149
+ }
2150
+
2151
+
2152
+
2153
+
2154
+
2155
+
2156
+
2157
+
2158
+ // Draw a grouped Bipolar chart, this is also the default
2159
+ } else if (typeof this.right[i] === 'object') {
2160
+
2161
+ for (var j=0; j<this.right[i].length; ++j) {
2162
+
2163
+ // If colorsSequential is specified - handle that
2164
+ // ** There's another instance of this further down **
2165
+ if (properties.colorsSequential) {
2166
+ this.context.fillStyle = properties.colors[sequentialColorIndex];
2167
+
2168
+ } else {
2169
+ this.context.fillStyle = properties.colors[j];
2170
+ }
2171
+
2172
+
2173
+
2174
+
2175
+ //
2176
+ // Work out the coordinates
2177
+ //
2178
+
2179
+ var value = this.right[i][j],
2180
+ min = this.min,
2181
+ max = this.max,
2182
+ margin = properties.marginInner,
2183
+ marginGrouped = properties.marginInnerGrouped,
2184
+
2185
+ width = ( (value - min) / (max - min)) * this.axisWidth,
2186
+ sectionHeight = (this.axisHeight / this.right.length),
2187
+ height = (sectionHeight - (2 * margin) - ( (this.right[i].length - 1) * marginGrouped)) / this.right[i].length,
2188
+ x = this.marginLeft + this.axisWidth + properties.marginCenter,
2189
+ y = this.marginTop + margin + (i * sectionHeight) + (height * j) + (j * marginGrouped);
2190
+
2191
+
2192
+ if (this.right[i] !== null) {
2193
+ this.context.strokeRect(x, y, width, height);
2194
+ this.context.fillRect(x, y, width, height);
2195
+ }
2196
+
2197
+
2198
+
2199
+
2200
+
2201
+
2202
+
2203
+
2204
+
2205
+
2206
+
2207
+
2208
+
2209
+ // Only store coordinates if this isn't a shadow iteration
2210
+ if (!opt.shadow) {
2211
+
2212
+
2213
+
2214
+ // Add the coordinates to the coords arrays
2215
+ this.coords.push([
2216
+ x,
2217
+ y,
2218
+ width,
2219
+ height
2220
+ ]);
2221
+
2222
+
2223
+
2224
+
2225
+ this.coordsRight.push([
2226
+ x,
2227
+ y,
2228
+ width,
2229
+ height
2230
+ ]);
2231
+
2232
+
2233
+
2234
+ // The .coords2 array
2235
+ if (!RGraph.isArray(this.coords2[this.left.length + i])) {
2236
+ this.coords2[this.left.length + i] = [];
2237
+ }
2238
+
2239
+ this.coords2[this.left.length + i].push([
2240
+ x,
2241
+ y,
2242
+ width,
2243
+ height
2244
+ ]);
2245
+
2246
+
2247
+
2248
+ if (!RGraph.isArray(this.coords2Right[i])) {
2249
+ this.coords2Right[i] = [];
2250
+ }
2251
+
2252
+ this.coords2Right[i].push([
2253
+ x,
2254
+ y,
2255
+ width,
2256
+ height
2257
+ ]);
2258
+ }
2259
+
2260
+ sequentialColorIndex++;
2261
+
2262
+
2263
+
2264
+
2265
+
2266
+
2267
+
2268
+
2269
+
2270
+
2271
+
2272
+
2273
+
2274
+
2275
+
2276
+
2277
+
2278
+ // Draw the 3D sides if required
2279
+ if (properties.variant === '3d' && this.right[i] !== null) {
2280
+
2281
+ var color = this.context.fillStyle;
2282
+
2283
+
2284
+ // If the shadow is enabled draw the backface for
2285
+ // (that we don't actually see
2286
+ if (properties.shadow && opt.shadow) {
2287
+
2288
+ this.context.shadowColor = properties.shadowColor;
2289
+ this.context.shadowBlur = properties.shadowBlur;
2290
+ this.context.shadowOffsetX = properties.shadowOffsetx;
2291
+ this.context.shadowOffsetY = properties.shadowOffsety;
2292
+
2293
+ this.path(
2294
+ 'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',
2295
+ x + offsetx, y - offsety,
2296
+ x + offsetx + width, y - offsety,
2297
+ x + offsetx + width, y - offsety + height,
2298
+ x + offsetx, y - offsety + height
2299
+ );
2300
+ }
2301
+
2302
+ // Draw the top
2303
+ this.path(
2304
+ 'b m % % l % % l % % l % % f %',
2305
+ x, y,
2306
+ x + offsetx, y - offsety,
2307
+ x + offsetx + width, y - offsety,
2308
+ x + width, y,
2309
+ color
2310
+ );
2311
+
2312
+
2313
+ // Draw the right hand side
2314
+ this.path(
2315
+ 'b m % % l % % l % % l % % f %',
2316
+ x + width,y,
2317
+ x + width + offsetx, y - offsety,
2318
+ x + width + offsetx, y - offsety + height,
2319
+ x + width,y + height,
2320
+ color
2321
+ );
2322
+
2323
+ // Draw the LIGHTER top
2324
+ this.path(
2325
+ 'b m % % l % % l % % l % % f rgba(255,255,255,0.6)',
2326
+ x,y,
2327
+ x + offsetx, y - offsety,
2328
+ x + offsetx + width, y - offsety,
2329
+ x + width, y
2330
+ );
2331
+
2332
+
2333
+ // Draw the DARKER right hand side
2334
+ this.path(
2335
+ 'b m % % l % % l % % l % % f rgba(0,0,0,0.3)',
2336
+ x + width,y,
2337
+ x + width + offsetx, y - offsety,
2338
+ x + width + offsetx, y - offsety + height,
2339
+ x + width,y + height
2340
+ );
2341
+ }
2342
+ }
2343
+ }
2344
+ }
2345
+
2346
+
2347
+
2348
+
2349
+
2350
+
2351
+ // If the colorsRight option is set then change
2352
+ // the colors option back to what it was.
2353
+ //
2354
+ if (!RGraph.isNull(properties.colorsRight)) {
2355
+ properties.colors = properties.colorsInitial;
2356
+ }
2357
+
2358
+
2359
+ //
2360
+ // Turn off any shadow
2361
+ //
2362
+ RGraph.noShadow(this);
2363
+
2364
+ // Reset the linewidth
2365
+ this.context.lineWidth = 1;
2366
+ };
2367
+
2368
+
2369
+
2370
+
2371
+
2372
+
2373
+
2374
+
2375
+ //
2376
+ // Draws the titles
2377
+ //
2378
+ this.drawLabels = function ()
2379
+ {
2380
+ var labels = properties.yaxisLabels,
2381
+ barAreaHeight = this.canvas.height - this.marginTop - this.marginBottom
2382
+
2383
+ // Get the text configuration
2384
+ var textConf = RGraph.getTextConf({
2385
+ object: this,
2386
+ prefix: 'yaxisLabels'
2387
+ });
2388
+
2389
+ this.context.fillStyle = textConf.color;
2390
+
2391
+ for (var i=0,len=labels.length; i<len; ++i) {
2392
+
2393
+ var ret = RGraph.text({
2394
+
2395
+ object: this,
2396
+
2397
+ color: textConf.color,
2398
+ font: textConf.font,
2399
+ size: textConf.size,
2400
+ bold: textConf.bold,
2401
+ italic: textConf.italic,
2402
+
2403
+ x: this.marginLeft + this.axisWidth + (properties.marginCenter / 2) + properties.yaxisLabelsOffsetx,
2404
+ y: this.marginTop + ((barAreaHeight / labels.length) * (i)) + ((barAreaHeight / labels.length) / 2) + properties.yaxisLabelsOffsety,
2405
+
2406
+ text: String(labels[i] ? String(labels[i]) : ''),
2407
+
2408
+ halign: 'center',
2409
+ valign: 'center',
2410
+
2411
+ marker: false,
2412
+ tag: 'labels',
2413
+ cssClass: RGraph.getLabelsCSSClassName({
2414
+ object: this,
2415
+ name: 'yaxisLabelsClass',
2416
+ index: i
2417
+ })
2418
+ });
2419
+ }
2420
+
2421
+
2422
+
2423
+ this.context.fillStyle = properties.textColor;
2424
+
2425
+
2426
+
2427
+
2428
+
2429
+
2430
+
2431
+
2432
+ if (properties.xaxisLabels) {
2433
+
2434
+ // Determine a few things
2435
+ var grapharea = (this.canvas.width - properties.marginCenter - this.marginLeft - this.marginRight) / 2;
2436
+
2437
+ var textConf = RGraph.getTextConf({
2438
+ object: this,
2439
+ prefix: 'xaxisLabels'
2440
+ });
2441
+
2442
+ // Now draw the X labels for the left hand side
2443
+ if (properties.leftVisible || properties.rightVisible) {
2444
+ for (var i=0; i<this.scale2.labels.length; ++i) {
2445
+
2446
+ // Draw the scale for the left-hand-side
2447
+ if (properties.leftVisible) {
2448
+ RGraph.text({
2449
+
2450
+ object: this,
2451
+
2452
+ font: textConf.font,
2453
+ size: textConf.size,
2454
+ bold: textConf.bold,
2455
+ italic: textConf.italic,
2456
+ color: textConf.color,
2457
+
2458
+ x: this.marginLeft + ((grapharea / this.scale2.labels.length) * i) - properties.xaxisLabelsOffsetx,
2459
+ y: this.canvas.height - this.marginBottom + 7 + properties.xaxisLabelsOffsety,
2460
+
2461
+ text: typeof properties.xaxisScaleFormatter === 'function' ? (properties.xaxisScaleFormatter)(this, this.scale2.values[this.scale2.values.length - i - 1]) : this.scale2.labels[this.scale2.labels.length - i - 1],
2462
+
2463
+ valign: 'top',
2464
+ halign: 'center',
2465
+ tag: 'scale'
2466
+ });
2467
+ }
2468
+
2469
+
2470
+
2471
+
2472
+ // Draw the scale for the right-hand-side
2473
+ if (properties.rightVisible) {
2474
+ RGraph.text({
2475
+
2476
+ object: this,
2477
+
2478
+ font: textConf.font,
2479
+ size: textConf.size,
2480
+ bold: textConf.bold,
2481
+ italic: textConf.italic,
2482
+ color: textConf.color,
2483
+
2484
+ x: this.marginLeft+ grapharea + properties.marginCenter + ((grapharea / this.scale2.labels.length) * (i + 1)) + properties.xaxisLabelsOffsetx,
2485
+ y: this.canvas.height - this.marginBottom + 7 + properties.xaxisLabelsOffsety,
2486
+
2487
+ text: this.scale2.labels[i],
2488
+ text: typeof properties.xaxisScaleFormatter === 'function' ? (properties.xaxisScaleFormatter)(this, this.scale2.values[i]) : this.scale2.labels[i],
2489
+
2490
+ valign: 'top',
2491
+ halign: 'center',
2492
+ tag: 'scale'
2493
+ });
2494
+ }
2495
+ }
2496
+ }
2497
+
2498
+
2499
+
2500
+
2501
+ // Draw zero?
2502
+ if (properties.xaxisScaleZerostart) {
2503
+
2504
+ // Draw zero for the left-hand-side
2505
+ if (properties.leftVisible) {
2506
+ RGraph.text({
2507
+
2508
+ object: this,
2509
+
2510
+ font: textConf.font,
2511
+ size: textConf.size,
2512
+ bold: textConf.bold,
2513
+ italic: textConf.italic,
2514
+ color: textConf.color,
2515
+
2516
+ x: this.marginLeft + this.axisWidth - properties.xaxisLabelsOffsetx,
2517
+ y: this.canvas.height - this.marginBottom + 7 + properties.xaxisLabelsOffsety,
2518
+
2519
+ text: typeof properties.xaxisScaleFormatter === 'function' ? (properties.xaxisScaleFormatter)(this, 0) : RGraph.numberFormat({
2520
+ object: this,
2521
+ number: (0).toFixed(properties.xaxisScaleDecimals),
2522
+ unitspre: properties.xaxisScaleUnitsPre,
2523
+ unitspost: properties.xaxisScaleUnitsPost
2524
+ }),
2525
+ valign: 'top',
2526
+ halign: 'center',
2527
+ tag: 'scale'
2528
+ });
2529
+ }
2530
+
2531
+
2532
+ // Draw zero for the right-hand-side
2533
+ if (properties.rightVisible) {
2534
+ RGraph.text({
2535
+
2536
+ object: this,
2537
+
2538
+ font: textConf.font,
2539
+ size: textConf.size,
2540
+ bold: textConf.bold,
2541
+ italic: textConf.italic,
2542
+ color: textConf.color,
2543
+
2544
+ x: this.marginLeft + this.axisWidth + this.marginCenter + properties.xaxisLabelsOffsetx,
2545
+ y: this.canvas.height - this.marginBottom + 7 + properties.xaxisLabelsOffsety,
2546
+
2547
+ text: typeof properties.xaxisScaleFormatter === 'function' ? (properties.xaxisScaleFormatter)(this, 0) : RGraph.numberFormat({
2548
+ object: this,
2549
+ number: (0).toFixed(properties.xaxisScaleDecimals),
2550
+ unitspre: properties.xaxisScaleUnitsPre,
2551
+ unitspost: properties.xaxisScaleUnitsPost
2552
+ }),
2553
+
2554
+ valign: 'top',
2555
+ halign: 'center',
2556
+
2557
+ tag: 'scale'
2558
+ });
2559
+ }
2560
+ }
2561
+ }
2562
+
2563
+
2564
+
2565
+
2566
+
2567
+ //
2568
+ // Draw above labels
2569
+ //
2570
+ if (properties.labelsAbove) {
2571
+ this.drawLabelsAbove();
2572
+ }
2573
+ };
2574
+
2575
+
2576
+
2577
+
2578
+
2579
+
2580
+
2581
+
2582
+ // This function draws the above labels
2583
+ this.drawLabelsAbove = function ()
2584
+ {
2585
+ var coordsLeft = this.coordsLeft,
2586
+ coordsRight = this.coordsRight;
2587
+
2588
+ // Get the text configuration
2589
+ var textConf = RGraph.getTextConf({
2590
+ object: this,
2591
+ prefix: 'labelsAbove'
2592
+ });
2593
+
2594
+ // Draw the left sides above labels
2595
+ for (var i=0,seq=0; i<coordsLeft.length; ++i, ++seq) {
2596
+
2597
+ if (typeof this.left[i] == 'number') {
2598
+
2599
+ var coords = this.coords[seq];
2600
+
2601
+ RGraph.text({
2602
+
2603
+ object: this,
2604
+
2605
+ font: textConf.font,
2606
+ size: textConf.size,
2607
+ bold: textConf.bold,
2608
+ italic: textConf.italic,
2609
+ color: textConf.color,
2610
+
2611
+ x: coords[0] - 5 - properties.labelsAboveOffsetx,
2612
+ y: coords[1] + (coords[3] / 2) + properties.labelsAboveOffsety,
2613
+
2614
+ text: typeof properties.labelsAboveFormatter === 'function' ? properties.labelsAboveFormatter(this, this.left[i]) : RGraph.numberFormat({
2615
+ object: this,
2616
+ number: this.left[i].toFixed(typeof properties.labelsAboveDecimals === 'number' ? properties.labelsAboveDecimals : 0),
2617
+ unitspre: properties.labelsAboveUnitsPre,
2618
+ unitspost: properties.labelsAboveUnitsPost
2619
+ }),
2620
+ valign: 'center',
2621
+ halign: 'right',
2622
+ tag: 'labels.above'
2623
+ });
2624
+
2625
+
2626
+
2627
+
2628
+
2629
+
2630
+ // A grouped or stacked chart
2631
+ } else if (typeof this.left[i] === 'object') {
2632
+
2633
+ // Loop through the group
2634
+
2635
+ for (var j=0; j<this.left[i].length; ++j,++seq) {
2636
+
2637
+ // Stacked charts only show the above label on the last
2638
+ // segment of the bar
2639
+ if (properties.grouping === 'stacked' && j !== (this.left[i].length - 1) ) {
2640
+ continue;
2641
+ }
2642
+
2643
+
2644
+ var coords = coordsLeft[seq];
2645
+
2646
+
2647
+ RGraph.text({
2648
+
2649
+ object: this,
2650
+
2651
+ font: textConf.font,
2652
+ size: textConf.size,
2653
+ bold: textConf.bold,
2654
+ italic: textConf.italic,
2655
+ color: textConf.color,
2656
+
2657
+ x: coords[0] - 5 - properties.labelsAboveOffsetx,
2658
+ y: coords[1] + (coords[3] / 2) + properties.labelsAboveOffsety,
2659
+ text: typeof properties.labelsAboveFormatter === 'function' ? properties.labelsAboveFormatter(this, this.left[i][j]) : RGraph.numberFormat({
2660
+ object: this,
2661
+ number: RGraph.isNull(this.left[i][j]) || isNaN(this.left[i][j]) ? '' : (properties.grouping === 'stacked' ? RGraph.arraySum(this.left[i]): Number(this.left[i][j])).toFixed(typeof properties.labelsAboveDecimals === 'number' ? properties.labelsAboveDecimals : 0),
2662
+ unitspre: properties.labelsAboveUnitsPre,
2663
+ unitspost: properties.labelsAboveUnitsPost
2664
+ }),
2665
+ valign: 'center',
2666
+ halign: 'right',
2667
+ tag: 'labels.above'
2668
+ });
2669
+ }
2670
+
2671
+ seq--;
2672
+ }
2673
+ }
2674
+
2675
+
2676
+
2677
+
2678
+
2679
+
2680
+
2681
+ // Draw the right sides above labels
2682
+ for (i=0,seq=0; i<coordsRight.length; ++i,++seq) {
2683
+
2684
+ if (typeof this.right[i] === 'number') {
2685
+
2686
+ var coords = coordsRight[seq];
2687
+
2688
+ RGraph.text({
2689
+
2690
+ object: this,
2691
+
2692
+ font: textConf.font,
2693
+ size: textConf.size,
2694
+ bold: textConf.bold,
2695
+ italic: textConf.italic,
2696
+ color: textConf.color,
2697
+
2698
+ x: coords[0] + coords[2] + 5 + (properties.variant === '3d' ? 10 : 0) + properties.labelsAboveOffsetx,
2699
+ y: coords[1] + (coords[3] / 2) + (properties.variant === '3d' ? -5 : 0) + properties.labelsAboveOffsety,
2700
+
2701
+ text: typeof properties.labelsAboveFormatter === 'function' ? properties.labelsAboveFormatter(this, this.right[i]) : RGraph.numberFormat({
2702
+ object: this,
2703
+ number: this.right[i].toFixed(typeof properties.labelsAboveDecimals === 'number' ? properties.labelsAboveDecimals : 0),
2704
+ unitspre: properties.labelsAboveUnitsPre,
2705
+ unitspost: properties.labelsAboveUnitsPost
2706
+ }),
2707
+ valign: 'center',
2708
+ halign: 'left',
2709
+ tag: 'labels.above'
2710
+ });
2711
+
2712
+
2713
+
2714
+
2715
+
2716
+ // A grouped/stacked chart
2717
+ } else if (typeof this.right[i] === 'object') {
2718
+
2719
+ // Loop through the group
2720
+ for (var j=0; j<this.right[i].length; ++j,++seq) {
2721
+
2722
+ // Stacked charts only show the above label on the last
2723
+ // segment of the bar
2724
+ if (properties.grouping === 'stacked' && j !== (this.right[i].length - 1)) {
2725
+ continue;
2726
+ }
2727
+
2728
+ var coords = coordsRight[seq];
2729
+
2730
+ RGraph.text({
2731
+
2732
+ object: this,
2733
+
2734
+ font: textConf.font,
2735
+ size: textConf.size,
2736
+ bold: textConf.bold,
2737
+ italic: textConf.italic,
2738
+ color: textConf.color,
2739
+
2740
+ x: coords[0] + coords[2] + 5 + (properties.variant === '3d' ? 10 : 0) + properties.labelsAboveOffsetx,
2741
+ y: coords[1] + (coords[3] / 2) + (properties.variant === '3d' ? -5 : 0) + properties.labelsAboveOffsety,
2742
+
2743
+ text: typeof properties.labelsAboveFormatter === 'function' ? properties.labelsAboveFormatter(this, this.right[i][j]) : RGraph.numberFormat({
2744
+ object: this,
2745
+ number: RGraph.isNull(this.right[i][j]) || isNaN(this.right[i][j]) ? '' : properties.grouping === 'stacked' ? RGraph.arraySum(this.right[i]).toFixed(properties.labelsAboveDecimals) : Number(this.right[i][j]).toFixed(typeof properties.labelsAboveDecimals === 'number' ? properties.labelsAboveDecimals : 0),
2746
+ unitspre: properties.labelsAboveUnitsPre,
2747
+ unitspost: properties.labelsAboveUnitsPost
2748
+ }),
2749
+ valign: 'center',
2750
+ halign: 'left',
2751
+ tag: 'labels.above'
2752
+ });
2753
+ }
2754
+
2755
+ --seq;
2756
+ }
2757
+ }
2758
+ };
2759
+
2760
+
2761
+
2762
+
2763
+
2764
+
2765
+
2766
+
2767
+ //
2768
+ // Draws the titles
2769
+ //
2770
+ this.drawTitles = function ()
2771
+ {
2772
+ // Make sure that the title subtitle are strings
2773
+ properties.titleLeft = String(properties.titleLeft);
2774
+ properties.titleRight = String(properties.titleRight);
2775
+ properties.title = String(properties.title);
2776
+
2777
+ // Draw the left title
2778
+ if (properties.titleLeft) {
2779
+
2780
+ // Get the text configuration
2781
+ var textConf = RGraph.getTextConf({
2782
+ object: this,
2783
+ prefix: 'titleLeft'
2784
+ });
2785
+
2786
+ RGraph.text({
2787
+
2788
+ object: this,
2789
+
2790
+ font: textConf.font,
2791
+ size: textConf.size,
2792
+ bold: textConf.bold,
2793
+ italic: textConf.italic,
2794
+ color: textConf.color,
2795
+
2796
+ x: this.marginLeft + 5 + properties.titleLeftOffsetx,
2797
+ y: this.marginTop - 5 + properties.titleLeftOffsety,
2798
+
2799
+ text: properties.titleLeft,
2800
+
2801
+ halign:'left',
2802
+ valign: 'bottom',
2803
+
2804
+ tag: 'title.left'
2805
+ });
2806
+ }
2807
+
2808
+
2809
+
2810
+
2811
+
2812
+
2813
+
2814
+
2815
+ // Draw the right title
2816
+ if (properties.titleRight) {
2817
+
2818
+ // Get the text configuration
2819
+ var textConf = RGraph.getTextConf({
2820
+ object: this,
2821
+ prefix: 'titleRight'
2822
+ });
2823
+
2824
+ RGraph.text({
2825
+
2826
+ object: this,
2827
+
2828
+ font: textConf.font,
2829
+ size: textConf.size,
2830
+ bold: textConf.bold,
2831
+ italic: textConf.italic,
2832
+ color: textConf.color,
2833
+
2834
+ x: this.canvas.width - this.marginRight - 5 + properties.titleRightOffsetx,
2835
+ y: this.marginTop - 5 + properties.titleRightOffsety,
2836
+
2837
+ text: properties.titleRight,
2838
+
2839
+ halign: 'right',
2840
+ valign: 'bottom',
2841
+
2842
+ tag: 'title.right'
2843
+ });
2844
+ }
2845
+
2846
+
2847
+ // Draw the main title for the whole chart
2848
+ if (properties.title) {
2849
+ RGraph.drawTitle(
2850
+ this,
2851
+ properties.title,
2852
+ this.marginTop,
2853
+ null,
2854
+ typeof properties.titleSize === 'number' ? properties.titleSize : null
2855
+ );
2856
+ }
2857
+ };
2858
+
2859
+
2860
+
2861
+
2862
+
2863
+
2864
+
2865
+
2866
+ //
2867
+ // Returns the appropriate focussed bar coordinates
2868
+ //
2869
+ // @param e object The event object
2870
+ //
2871
+ this.getShape = function (e)
2872
+ {
2873
+ var canvas = this.canvas,
2874
+ context = this.context,
2875
+ mouseXY = RGraph.getMouseXY(e),
2876
+ side = 0; // Default to the left side
2877
+
2878
+ //
2879
+ // Loop through the bars determining if the mouse is over a bar
2880
+ //
2881
+ for (var i=0; i<this.coords.length; i++) {
2882
+
2883
+ if (RGraph.tooltipsHotspotIgnore(this, i)) {
2884
+ continue;
2885
+ }
2886
+
2887
+ var mouseX = mouseXY[0],
2888
+ mouseY = mouseXY[1],
2889
+ left = this.coords[i][0],
2890
+ top = this.coords[i][1],
2891
+ width = this.coords[i][2],
2892
+ height = this.coords[i][3]
2893
+
2894
+
2895
+ //if (properties.variant === '3d') {
2896
+ // Now ( 23/10/2019 use path checking always - not just for 3D charts
2897
+ this.path(
2898
+ 'b r % % % %',
2899
+ left,top,width,height
2900
+ );
2901
+
2902
+ var over = this.context.isPointInPath(mouseX, mouseY);
2903
+
2904
+ // Is the mouse cursor over a shape?
2905
+ if (over) {
2906
+
2907
+ if (RGraph.parseTooltipText) {
2908
+ var tooltip = RGraph.parseTooltipText(properties.tooltips, i);
2909
+ }
2910
+
2911
+ var indexes = RGraph.sequentialIndexToGrouped(i, this.data2),
2912
+ group = indexes[0],
2913
+ index = indexes[1],
2914
+ group2 = group;
2915
+
2916
+ // Work out the group2 variable
2917
+ if ( (group +1) > this.left.length) {
2918
+ group2 -= this.left.length;
2919
+ side = 1;// Right-hand-side
2920
+ }
2921
+
2922
+ return {
2923
+ object: this,
2924
+ x: left,
2925
+ y: top,
2926
+ width: width,
2927
+ height: height,
2928
+ tooltip: typeof tooltip === 'string' ? tooltip : null,
2929
+ side: side,
2930
+ sequentialIndex: i,
2931
+ index: index,
2932
+ dataset: group,
2933
+ dataset2: group2,
2934
+ label: properties.yaxisLabels && typeof properties.yaxisLabels[group2] === 'string' ? properties.yaxisLabels[group2] : null
2935
+ };
2936
+ }
2937
+ }
2938
+
2939
+ return null;
2940
+ };
2941
+
2942
+
2943
+
2944
+
2945
+
2946
+
2947
+
2948
+
2949
+ //
2950
+ // Each object type has its own Highlight() function which highlights the appropriate shape
2951
+ //
2952
+ // @param object shape The shape to highlight
2953
+ //
2954
+ this.highlight = function (shape)
2955
+ {
2956
+ if (typeof properties.highlightStyle === 'function') {
2957
+ (properties.highlightStyle)(shape);
2958
+
2959
+ // Highlight all of the rects except this one - essentially an inverted highlight
2960
+ } else if (typeof properties.highlightStyle === 'string' && properties.highlightStyle === 'invert') {
2961
+ for (var i=0; i<this.coords.length; ++i) {
2962
+ if (i !== shape.sequentialIndex) {
2963
+ this.path(
2964
+ 'b r % % % % s % f %',
2965
+ this.coords[i][0] - 0.5, this.coords[i][1] - 0.5, this.coords[i][2] + 1, this.coords[i][3] + 1,
2966
+ properties.highlightStroke,
2967
+ properties.highlightFill
2968
+ );
2969
+ }
2970
+ }
2971
+
2972
+ } else {
2973
+ RGraph.Highlight.rect(this, shape);
2974
+ }
2975
+ };
2976
+
2977
+
2978
+
2979
+
2980
+
2981
+
2982
+
2983
+
2984
+ //
2985
+ // When you click on the canvas, this will return the relevant value (if any)
2986
+ //
2987
+ // REMEMBER This function will need updating if the Bipolar ever gets yaxisScaleMin
2988
+ //
2989
+ // @param object e The event object
2990
+ //
2991
+ this.getValue = function (e)
2992
+ {
2993
+ var obj = e.target.__object__;
2994
+ var mouseXY = RGraph.getMouseXY(e);
2995
+ var mouseX = mouseXY[0];
2996
+
2997
+ //
2998
+ // Left hand side
2999
+ //
3000
+ if (mouseX > this.marginLeft && mouseX < ( (this.canvas.width / 2) - (properties.marginCenter / 2) )) {
3001
+ var value = (mouseX - properties.marginLeft) / this.axisWidth;
3002
+ value = this.max - (value * this.max);
3003
+ }
3004
+
3005
+ //
3006
+ // Right hand side
3007
+ //
3008
+ if (mouseX < (this.canvas.width - this.marginRight) && mouseX > ( (this.canvas.width / 2) + (properties.marginCenter / 2) )) {
3009
+ var value = (mouseX - properties.marginLeft - this.axisWidth - properties.marginCenter) / this.axisWidth;
3010
+ value = (value * this.max);
3011
+ }
3012
+
3013
+ return value;
3014
+ };
3015
+
3016
+
3017
+
3018
+
3019
+
3020
+
3021
+
3022
+
3023
+ //
3024
+ // The getObjectByXY() worker method. Don't call this call:
3025
+ //
3026
+ // RGraph.ObjectRegistry.getObjectByXY(e)
3027
+ //
3028
+ // @param object e The event object
3029
+ //
3030
+ this.getObjectByXY = function (e)
3031
+ {
3032
+ var mouseXY = RGraph.getMouseXY(e);
3033
+
3034
+ if (properties.variant === '3d' && !properties.textAccessible) {
3035
+ var adjustment = properties.variantThreedAngle * mouseXY[0];
3036
+ mouseXY[1] -= adjustment;
3037
+ }
3038
+
3039
+ if (
3040
+ mouseXY[0] > properties.marginLeft
3041
+ && mouseXY[0] < (this.canvas.width - properties.marginRight)
3042
+ && mouseXY[1] > properties.marginTop
3043
+ && mouseXY[1] < (this.canvas.height - properties.marginBottom)
3044
+ ) {
3045
+
3046
+ return this;
3047
+ }
3048
+ };
3049
+
3050
+
3051
+
3052
+
3053
+
3054
+
3055
+
3056
+
3057
+ //
3058
+ // Returns the X coords for a value. Returns two coords because there are... two scales.
3059
+ //
3060
+ // @param number value The value to get the coord for
3061
+ //
3062
+ this.getXCoord = function (value)
3063
+ {
3064
+ if (value > this.max || value < 0) {
3065
+ return null;
3066
+ }
3067
+
3068
+ var ret = [];
3069
+
3070
+ // The offset into the graph area
3071
+ var offset = ((value / this.max) * this.axisWidth);
3072
+
3073
+ // Get the coords (one fo each side)
3074
+ ret[0] = (this.marginLeft + this.axisWidth) - offset;
3075
+ ret[1] = (this.canvas.width - this.marginRight - this.axisWidth) + offset;
3076
+
3077
+ return ret;
3078
+ };
3079
+
3080
+
3081
+
3082
+
3083
+
3084
+
3085
+
3086
+
3087
+ //
3088
+ // This allows for easy specification of gradients
3089
+ //
3090
+ this.parseColors = function ()
3091
+ {
3092
+ // Save the original colors so that they can be restored when the canvas is reset
3093
+ if (this.original_colors.length === 0) {
3094
+ this.original_colors.colors = RGraph.arrayClone(properties.colors);
3095
+ this.original_colors.highlightStroke = RGraph.arrayClone(properties.highlightStroke);
3096
+ this.original_colors.highlightFill = RGraph.arrayClone(properties.highlightFill);
3097
+ this.original_colors.axesColor = RGraph.arrayClone(properties.axesColor);
3098
+ this.original_colors.colorsStroke = RGraph.arrayClone(properties.colorsStroke);
3099
+ this.original_colors.colorsLeft = RGraph.arrayClone(properties.colorsLeft);
3100
+ this.original_colors.colorsRight = RGraph.arrayClone(properties.colorsRight);
3101
+ this.original_colors.keyColors = RGraph.arrayClone(properties.keyColors);
3102
+ }
3103
+
3104
+ var colors = properties.colors;
3105
+
3106
+ for (var i=0; i<colors.length; ++i) {
3107
+ colors[i] = this.parseSingleColorForGradient(colors[i]);
3108
+ }
3109
+
3110
+ if (RGraph.isArray(properties.colorsLeft)) {
3111
+ for (var i=0; i<properties.colorsLeft.length; ++i) {
3112
+ properties.colorsLeft[i] = this.parseSingleColorForGradient(properties.colorsLeft[i]);
3113
+ }
3114
+ }
3115
+
3116
+ if (RGraph.isArray(properties.colorsRight)) {
3117
+ for (var i=0; i<properties.colorsRight.length; ++i) {
3118
+ properties.colorsRight[i] = this.parseSingleColorForGradient(properties.colorsRight[i]);
3119
+ }
3120
+ }
3121
+
3122
+ // keyColors
3123
+ var colors = properties.keyColors;
3124
+ if (colors) {
3125
+ for (var i=0; i<colors.length; ++i) {
3126
+ colors[i] = this.parseSingleColorForGradient(colors[i]);
3127
+ }
3128
+ }
3129
+
3130
+ properties.highlightStroke = this.parseSingleColorForGradient(properties.highlightStroke);
3131
+ properties.highlightFill = this.parseSingleColorForGradient(properties.highlightFill);
3132
+ properties.axesColor = this.parseSingleColorForGradient(properties.axesColor);
3133
+ properties.colorsStroke = this.parseSingleColorForGradient(properties.colorsStroke);
3134
+ };
3135
+
3136
+
3137
+
3138
+
3139
+
3140
+
3141
+
3142
+
3143
+ //
3144
+ // Use this function to reset the object to the post-constructor state. Eg reset colors if
3145
+ // need be etc
3146
+ //
3147
+ this.reset = function ()
3148
+ {
3149
+ };
3150
+
3151
+
3152
+
3153
+
3154
+
3155
+
3156
+
3157
+
3158
+ //
3159
+ // This parses a single color value
3160
+ //
3161
+ this.parseSingleColorForGradient = function (color)
3162
+ {
3163
+ if (!color || typeof color != 'string') {
3164
+ return color;
3165
+ }
3166
+
3167
+ if (color.match(/^gradient\((.*)\)$/i)) {
3168
+
3169
+ // Allow for JSON gradients
3170
+ if (color.match(/^gradient\(({.*})\)$/i)) {
3171
+ return RGraph.parseJSONGradient({object: this, def: RegExp.$1});
3172
+ }
3173
+
3174
+ var parts = RegExp.$1.split(':');
3175
+
3176
+ // Create the gradient
3177
+ var grad = this.context.createLinearGradient(properties.marginLeft,0,this.canvas.width - properties.marginRight,0);
3178
+
3179
+ var diff = 1 / (parts.length - 1);
3180
+
3181
+ grad.addColorStop(0, RGraph.trim(parts[0]));
3182
+
3183
+ for (var j=1; j<parts.length; ++j) {
3184
+ grad.addColorStop(j * diff, RGraph.trim(parts[j]));
3185
+ }
3186
+ }
3187
+
3188
+ return grad ? grad : color;
3189
+ };
3190
+
3191
+
3192
+
3193
+
3194
+
3195
+
3196
+
3197
+
3198
+ //
3199
+ // This function handles highlighting an entire data-series for the interactive
3200
+ // key
3201
+ //
3202
+ // @param int index The index of the data series to be highlighted
3203
+ //
3204
+ this.interactiveKeyHighlight = function (index)
3205
+ {
3206
+ for (var i=0; i<this.coords2.length; ++i) {
3207
+
3208
+ var coords = this.coords2[i][index];
3209
+
3210
+ // Draw some highlight over the top of the bar
3211
+ this.path(
3212
+ 'b r % % % % s % f %',
3213
+
3214
+ coords[0],
3215
+ coords[1],
3216
+ coords[2],
3217
+ coords[3],
3218
+
3219
+ properties.keyInteractiveHighlightChartStroke,
3220
+ properties.keyInteractiveHighlightChartFill
3221
+ );
3222
+ }
3223
+
3224
+ };
3225
+
3226
+
3227
+
3228
+
3229
+
3230
+
3231
+
3232
+
3233
+ //
3234
+ // Using a function to add events makes it easier to facilitate method chaining
3235
+ //
3236
+ // @param string type The type of even to add
3237
+ // @param function func
3238
+ //
3239
+ this.on = function (type, func)
3240
+ {
3241
+ if (type.substr(0,2) !== 'on') {
3242
+ type = 'on' + type;
3243
+ }
3244
+
3245
+ if (typeof this[type] !== 'function') {
3246
+ this[type] = func;
3247
+ } else {
3248
+ RGraph.addCustomEventListener(this, type, func);
3249
+ }
3250
+
3251
+ return this;
3252
+ };
3253
+
3254
+
3255
+
3256
+
3257
+
3258
+
3259
+
3260
+
3261
+ //
3262
+ // Draw the background grid
3263
+ //
3264
+ this.drawBackgroundGrid = function ()
3265
+ {
3266
+ if (properties.backgroundGrid) {
3267
+
3268
+ var variant = properties.variant,
3269
+ color = properties.backgroundGridColor,
3270
+ numvlines = properties.xaxisLabelsCount, // TODO Should this be based on the data - not the labels...?
3271
+ numhlines = this.left.length,
3272
+ vlines = properties.backgroundGridVlines,
3273
+ hlines = properties.backgroundGridHlines,
3274
+ linewidth = properties.backgroundGridLinewidth;
3275
+
3276
+ // Autofit
3277
+ if (typeof properties.backgroundGridHlinesCount === 'number') {
3278
+ numhlines = properties.backgroundGridHlinesCount;
3279
+ }
3280
+
3281
+ if (typeof properties.backgroundGridVlinesCount === 'number') {
3282
+ numvlines = properties.backgroundGridVlinesCount;
3283
+ }
3284
+
3285
+ this.context.lineWidth = linewidth;
3286
+
3287
+ // If it's a bar and 3D variant, translate
3288
+ if (variant == '3d') {
3289
+ this.context.save();
3290
+ this.context.translate(
3291
+ properties.variantThreedOffsetx,
3292
+ -1 * properties.variantThreedOffsety
3293
+ );
3294
+ }
3295
+
3296
+ // Draw vertical grid lines for the left side
3297
+ if (properties.leftVisible) {
3298
+ if (vlines) {
3299
+ for (var i=0; i<=numvlines; i+=1) {
3300
+ this.path(
3301
+ 'b m % % l % % s %',
3302
+ this.marginLeft + (this.axisWidth / numvlines) * i, this.marginTop,
3303
+ this.marginLeft + (this.axisWidth / numvlines) * i, this.marginTop + this.axisHeight,
3304
+ color
3305
+ );
3306
+ }
3307
+ }
3308
+
3309
+ // Draw horizontal grid lines for the left side
3310
+ if (hlines) {
3311
+ for (var i=0; i<=numhlines; i+=1) {
3312
+ this.path(
3313
+ 'b m % % l % % s %',
3314
+ this.marginLeft, this.marginTop + (this.axisHeight / numhlines) * i,
3315
+ this.marginLeft + this.axisWidth, this.marginTop + (this.axisHeight / numhlines) * i,
3316
+ color
3317
+ );
3318
+ }
3319
+ }
3320
+ }
3321
+
3322
+
3323
+ // Draw vertical grid lines for the right side
3324
+ if (properties.rightVisible) {
3325
+ if (vlines) {
3326
+ for (var i=0; i<=numvlines; i+=1) {
3327
+ this.path(
3328
+ 'b m % % l % % s %',
3329
+ this.marginLeft + this.marginCenter + this.axisWidth + (this.axisWidth / numvlines) * i, this.marginTop,
3330
+ this.marginLeft + this.marginCenter + this.axisWidth + (this.axisWidth / numvlines) * i, this.marginTop + this.axisHeight,
3331
+ color
3332
+ );
3333
+ }
3334
+ }
3335
+
3336
+ // Draw horizontal grid lines for the right side
3337
+ if (hlines) {
3338
+ for (var i=0; i<=numhlines; i+=1) {
3339
+ this.path(
3340
+ 'b m % % l % % s %',
3341
+ this.marginLeft + this.axisWidth + this.marginCenter, this.marginTop + (this.axisHeight / numhlines) * i,
3342
+ this.marginLeft + this.axisWidth + this.marginCenter + this.axisWidth, this.marginTop + (this.axisHeight / numhlines) * i,
3343
+ color
3344
+ );
3345
+ }
3346
+ }
3347
+ }
3348
+
3349
+
3350
+ // If it's a bar and 3D variant, translate
3351
+ if (variant == '3d') {
3352
+ this.context.restore();
3353
+ }
3354
+ }
3355
+ };
3356
+
3357
+
3358
+
3359
+
3360
+
3361
+
3362
+
3363
+
3364
+ //
3365
+ // This function runs once only
3366
+ // (put at the end of the file (before any effects))
3367
+ //
3368
+ this.firstDrawFunc = function ()
3369
+ {
3370
+ };
3371
+
3372
+
3373
+
3374
+
3375
+
3376
+
3377
+
3378
+
3379
+ //
3380
+ // Calulate the center margin size
3381
+ //
3382
+ this.getMarginCenter = function ()
3383
+ {
3384
+ var bold = typeof properties.yaxisLabelsBold === 'boolean' ? properties.yaxisLabelsBold : properties.textBold,
3385
+ font = typeof properties.yaxisLabelsFont === 'string' ? properties.yaxisLabelsFont : properties.textFont,
3386
+ size = typeof properties.yaxisLabelsSize === 'number' ? properties.yaxisLabelsSize : properties.textSize;
3387
+
3388
+ // Loop through the labels measuring them
3389
+ for (var i=0,len=0; i<properties.yaxisLabels.length; ++i) {
3390
+
3391
+ len = Math.max(len, RGraph.measureText(
3392
+ properties.yaxisLabels[i],
3393
+ bold,
3394
+ font,
3395
+ size
3396
+ )[0]);
3397
+ }
3398
+
3399
+ return len + 25;
3400
+ };
3401
+
3402
+
3403
+
3404
+
3405
+
3406
+
3407
+
3408
+
3409
+ //
3410
+ // Grow
3411
+ //
3412
+ // The Bipolar chart Grow effect gradually increases the values of the bars
3413
+ //
3414
+ // @param object An object of options - eg: {frames: 30}
3415
+ // @param function A function to call when the effect is complete
3416
+ //
3417
+ this.grow = function ()
3418
+ {
3419
+ // Cancel any stop request if one is pending
3420
+ this.cancelStopAnimation();
3421
+
3422
+ // Callback
3423
+ var opt = arguments[0] || {},
3424
+ frames = opt.frames || 30,
3425
+ frame = 0,
3426
+ callback = arguments[1] || function () {},
3427
+ obj = this;
3428
+
3429
+ // Save the data
3430
+ var originalLeft = RGraph.arrayClone(this.left),
3431
+ originalRight = RGraph.arrayClone(this.right);
3432
+
3433
+
3434
+ // Stop the scale from changing by setting xaxisScaleMax (if it's
3435
+ // not already set)
3436
+ if (RGraph.isNull(properties.xaxisScaleMax)) {
3437
+
3438
+ var xmax = 0;
3439
+
3440
+ // Get the max values
3441
+ this.getMax();
3442
+
3443
+ this.set('xaxisScaleMax', this.scale2.max);
3444
+ }
3445
+
3446
+ var iterator = function ()
3447
+ {
3448
+ if (obj.stopAnimationRequested_left || obj.stopAnimationRequested_right) {
3449
+
3450
+ // Reset the flag
3451
+ obj.stopAnimationRequested_left = false;
3452
+ obj.stopAnimationRequested_right = false;
3453
+
3454
+ // Reset the data
3455
+ obj.left = RGraph.arrayClone(originalLeft);
3456
+ obj.right = RGraph.arrayClone(originalRight);
3457
+
3458
+ return;
3459
+ }
3460
+
3461
+ var easingMultiplier = RGraph.Effects.getEasingMultiplier(frames, frame);
3462
+
3463
+ // Left hand side
3464
+ for (var i=0; i<obj.left.length; i+=1) {
3465
+ if (typeof obj.left[i] === 'number') {
3466
+ obj.left[i] = easingMultiplier * originalLeft[i];
3467
+ } else {
3468
+ for (var j=0; j<obj.left[i].length; ++j) {
3469
+ obj.left[i][j] = easingMultiplier * originalLeft[i][j];
3470
+ }
3471
+ }
3472
+ }
3473
+
3474
+ // Right hand side
3475
+ for (var i=0; i<obj.right.length; i+=1) {
3476
+ if (typeof obj.right[i] === 'number') {
3477
+ obj.right[i] = easingMultiplier * originalRight[i];
3478
+ } else {
3479
+ for (var j=0; j<obj.right[i].length; ++j) {
3480
+ obj.right[i][j] = easingMultiplier * originalRight[i][j];
3481
+ }
3482
+ }
3483
+ }
3484
+
3485
+ RGraph.redrawCanvas(obj.canvas);
3486
+
3487
+ // Repeat or call the end function if one is defined
3488
+ if (frame < frames) {
3489
+ frame += 1;
3490
+ RGraph.Effects.updateCanvas(iterator);
3491
+ } else {
3492
+ callback(obj);
3493
+ }
3494
+ };
3495
+
3496
+ iterator();
3497
+
3498
+ return this;
3499
+ };
3500
+
3501
+
3502
+
3503
+
3504
+
3505
+
3506
+
3507
+
3508
+ //
3509
+ // Bipolar chart Wave effect.
3510
+ //
3511
+ // @param object OPTIONAL An object map of options. You specify 'frames' here to give the number of frames in the effect
3512
+ // @param function OPTIONAL A function that will be called when the effect is complete
3513
+ //
3514
+ this.wave = function ()
3515
+ {
3516
+ this.cancelStopAnimation();
3517
+
3518
+ var obj = this,
3519
+ opt = arguments[0] || {};
3520
+ opt.frames = opt.frames || 120;
3521
+ opt.startFrames_left = [];
3522
+ opt.startFrames_right = [];
3523
+ opt.counters_left = [];
3524
+ opt.counters_right = [];
3525
+
3526
+ var framesperbar = opt.frames / 3,
3527
+ frame_left = -1,
3528
+ frame_right = -1,
3529
+ callback = arguments[1] || function () {},
3530
+ original_left = RGraph.arrayClone(obj.left),
3531
+ original_right = RGraph.arrayClone(obj.right);
3532
+
3533
+ for (var i=0,len=obj.left.length; i<len; i+=1) {
3534
+ opt.startFrames_left[i] = ((opt.frames / 3) / (obj.left.length - 1)) * i;
3535
+ opt.startFrames_right[i] = ((opt.frames / 3) / (obj.right.length - 1)) * i;
3536
+ opt.counters_left[i] = 0;
3537
+ opt.counters_right[i] = 0;
3538
+ }
3539
+
3540
+ // This stops the chart from jumping
3541
+ obj.draw();
3542
+ obj.set('xaxisScaleMax', obj.scale2.max);
3543
+ RGraph.clear(obj.canvas);
3544
+
3545
+
3546
+ // Zero all of the data
3547
+ for (var i=0,len=obj.left.length; i<len; i+=1) {
3548
+ if (typeof obj.left[i] === 'number') obj.left[i] = 0;
3549
+ if (typeof obj.right[i] === 'number') obj.right[i] = 0;
3550
+ }
3551
+
3552
+ //
3553
+ // Iterate over the left side
3554
+ //
3555
+ function iteratorLeft ()
3556
+ {
3557
+ if (obj.stopAnimationRequested_left) {
3558
+
3559
+ // Reset the flag
3560
+ obj.stopAnimationRequested_left = false;
3561
+
3562
+ // Reset the data
3563
+ obj.left = RGraph.arrayClone(original_left);
3564
+
3565
+ return;
3566
+ }
3567
+
3568
+ ++frame_left;
3569
+
3570
+ for (var i=0,len=obj.left.length; i<len; i+=1) {
3571
+ if (frame_left > opt.startFrames_left[i]) {
3572
+
3573
+ var isNull = RGraph.isNull(obj.left[i]);
3574
+
3575
+ // Regular bars
3576
+ if (typeof obj.left[i] === 'number') {
3577
+ obj.left[i] = Math.min(
3578
+ Math.abs(original_left[i]),
3579
+ Math.abs(original_left[i] * ( (opt.counters_left[i]++) / framesperbar))
3580
+ );
3581
+
3582
+ // Make the number negative if the original was
3583
+ if (original_left[i] < 0) {
3584
+ obj.left[i] *= -1;
3585
+ }
3586
+
3587
+
3588
+ // Stacked or grouped bars
3589
+ } else if (RGraph.isArray(obj.left[i])) {
3590
+ for (var j=0; j<obj.left[i].length; ++j) {
3591
+ obj.left[i][j] = Math.min(
3592
+ Math.abs(original_left[i][j]),
3593
+ Math.abs(original_left[i][j] * ( (opt.counters_left[i]++) / framesperbar))
3594
+ );
3595
+
3596
+ // Make the number negative if the original was
3597
+ if (original_left[i][j] < 0) {
3598
+ obj.left[i][j] *= -1;
3599
+ }
3600
+ }
3601
+ }
3602
+
3603
+ if (isNull) {
3604
+ obj.left[i] = null;
3605
+ }
3606
+ } else {
3607
+ obj.left[i] = typeof obj.left[i] === 'object' && obj.left[i] ? RGraph.arrayPad([], obj.left[i].length, 0) : (RGraph.isNull(obj.left[i]) ? null : 0);
3608
+ }
3609
+
3610
+ }
3611
+
3612
+
3613
+ // No callback here - only called by the right function
3614
+ if (frame_left < opt.frames) {
3615
+ RGraph.redrawCanvas(obj.canvas);
3616
+ RGraph.Effects.updateCanvas(iteratorLeft);
3617
+ }
3618
+ }
3619
+
3620
+
3621
+
3622
+
3623
+ //
3624
+ // Iterate over the right side
3625
+ //
3626
+ function iteratorRight ()
3627
+ {
3628
+ if (obj.stopAnimationRequested_right) {
3629
+
3630
+ // Reset the flag
3631
+ obj.stopAnimationRequested_right = false;
3632
+
3633
+ // Reset the data
3634
+ obj.right = RGraph.arrayClone(original_right);
3635
+
3636
+ return;
3637
+ }
3638
+
3639
+ ++frame_right;
3640
+
3641
+ for (var i=0,len=obj.right.length; i<len; i+=1) {
3642
+ if (frame_right > opt.startFrames_right[i]) {
3643
+
3644
+ var isNull = RGraph.isNull(obj.right[i]);
3645
+
3646
+ if (typeof obj.left[i] === 'number') {
3647
+ obj.right[i] = Math.min(
3648
+ Math.abs(original_right[i]),
3649
+ Math.abs(original_right[i] * ( (opt.counters_right[i]++) / framesperbar))
3650
+ );
3651
+
3652
+ // Make the number negative if the original was
3653
+ if (original_right[i] < 0) {
3654
+ obj.right[i] *= -1;
3655
+ }
3656
+
3657
+ if (isNull) {
3658
+ obj.right[i] = null;
3659
+ }
3660
+ } else if (RGraph.isArray(obj.right[i])) {
3661
+ for (var j=0; j<obj.right[i].length; ++j) {
3662
+ obj.right[i][j] = Math.min(
3663
+ Math.abs(original_right[i][j]),
3664
+ Math.abs(original_right[i][j] * ( (opt.counters_right[i]++) / framesperbar))
3665
+ );
3666
+
3667
+ // Make the number negative if the original was
3668
+ if (original_right[i][j] < 0) {
3669
+ obj.right[i][j] *= -1;
3670
+ }
3671
+ }
3672
+ }
3673
+
3674
+ } else {
3675
+ obj.right[i] = typeof obj.right[i] === 'object' && obj.right[i] ? RGraph.arrayPad([], obj.right[i].length, 0) : (RGraph.isNull(obj.right[i]) ? null : 0);
3676
+ }
3677
+ }
3678
+
3679
+
3680
+ // No callback here - only called by the right function
3681
+ if (frame_right < opt.frames) {
3682
+ RGraph.redrawCanvas(obj.canvas);
3683
+ RGraph.Effects.updateCanvas(iteratorRight);
3684
+ } else {
3685
+ callback(this);
3686
+ }
3687
+ }
3688
+
3689
+
3690
+
3691
+
3692
+ iteratorLeft();
3693
+ iteratorRight();
3694
+
3695
+ return this;
3696
+ };
3697
+
3698
+
3699
+
3700
+
3701
+
3702
+
3703
+
3704
+
3705
+ //
3706
+ // Couple of functions that allow you to control the
3707
+ // Bipolar animation effects
3708
+ //
3709
+ this.stopAnimation = function ()
3710
+ {
3711
+ this.stopAnimationRequested_left = true;
3712
+ this.stopAnimationRequested_right = true;
3713
+ };
3714
+
3715
+ this.cancelStopAnimation = function ()
3716
+ {
3717
+ this.stopAnimationRequested_left = false;
3718
+ this.stopAnimationRequested_right = false;
3719
+ };
3720
+
3721
+
3722
+
3723
+
3724
+
3725
+
3726
+
3727
+
3728
+ //
3729
+ // A worker function that handles Bipolar chart specific tooltip substitutions
3730
+ //
3731
+ this.tooltipSubstitutions = function (opt)
3732
+ {
3733
+ var indexes = RGraph.sequentialIndexToGrouped(opt.index, this.data2);
3734
+
3735
+ // Calculate the dataset that can be used in labels//
3736
+ if (indexes[0] >= this.left.length) {
3737
+ var dataset2 = indexes[0] - this.left.length,
3738
+ side = 'right',
3739
+ values = this.right[dataset2];
3740
+ } else {
3741
+ var dataset2 = indexes[0],
3742
+ side = 'left'
3743
+ values = this.left[dataset2];
3744
+ }
3745
+
3746
+ if (typeof values === 'number') {
3747
+ values = [values];
3748
+ }
3749
+
3750
+ return {
3751
+ index: indexes[1],
3752
+ dataset: indexes[0],
3753
+ dataset2: dataset2,
3754
+ sequentialIndex: opt.index,
3755
+ value: typeof this.data2[opt.index] === 'number' ? this.data2[opt.index] : this.data2[indexes[0]][indexes[1]],
3756
+ values: values,
3757
+ side: side
3758
+ };
3759
+ };
3760
+
3761
+
3762
+
3763
+
3764
+
3765
+
3766
+
3767
+
3768
+ //
3769
+ // A worker function that returns the correct color/label/value
3770
+ //
3771
+ // @param object specific The indexes that are applicable
3772
+ // @param number index The appropriate index
3773
+ //
3774
+ this.tooltipsFormattedCustom = function (specific, index)
3775
+ {
3776
+ var label;
3777
+ var side = ((specific.dataset + 1) > this.left.length) ? 'right' : 'left';
3778
+
3779
+ if (typeof this[side][specific.dataset2] === 'object') {
3780
+
3781
+ label = (!RGraph.isNull(properties.tooltipsFormattedKeyLabels) && typeof properties.tooltipsFormattedKeyLabels === 'object' && properties.tooltipsFormattedKeyLabels[index])
3782
+ ? properties.tooltipsFormattedKeyLabels[index]
3783
+ : '';
3784
+
3785
+ } else {
3786
+ label = (!RGraph.isNull(properties.tooltipsFormattedKeyLabels) && typeof properties.tooltipsFormattedKeyLabels === 'object' && properties.tooltipsFormattedKeyLabels[specific.index])
3787
+ ? properties.tooltipsFormattedKeyLabels[specific.index]
3788
+ : '';
3789
+ }
3790
+
3791
+ return {
3792
+ label: label
3793
+ };
3794
+ };
3795
+
3796
+
3797
+
3798
+
3799
+
3800
+
3801
+
3802
+
3803
+ //
3804
+ // This allows for static tooltip positioning
3805
+ //
3806
+ this.positionTooltipStatic = function (args)
3807
+ {
3808
+ var obj = args.object,
3809
+ e = args.event,
3810
+ tooltip = args.tooltip,
3811
+ index = args.index,
3812
+ canvasXY = RGraph.getCanvasXY(obj.canvas)
3813
+ coords = this.coords[args.index];
3814
+
3815
+ // Position the tooltip in the X direction
3816
+ args.tooltip.style.left = (
3817
+ canvasXY[0] // The X coordinate of the canvas
3818
+ + coords[0] // The X coordinate of the point on the chart
3819
+ + (coords[2] / 2) // Add half of the width of the bar
3820
+ - (tooltip.offsetWidth / 2) // Subtract half of the tooltip width
3821
+ + obj.properties.tooltipsOffsetx // Add any user defined offset
3822
+ ) + 'px';
3823
+
3824
+ args.tooltip.style.top = (
3825
+ canvasXY[1] // The Y coordinate of the canvas
3826
+ + coords[1] // The Y coordinate of the bar on the chart
3827
+ - tooltip.offsetHeight // The height of the tooltip
3828
+ - 10 // An arbitrary amount
3829
+ + obj.properties.tooltipsOffsety // Add any user defined offset
3830
+ ) + 'px';
3831
+
3832
+
3833
+
3834
+ // If the chart is a 3D version the tooltip Y position needs this
3835
+ // adjustment
3836
+ if (properties.variant === '3d') {
3837
+
3838
+ var left = coords[0];
3839
+ var top = coords[1];
3840
+ var angle = properties.variantThreedAngle;
3841
+ var adjustment = Math.tan(angle) * left;
3842
+
3843
+ args.tooltip.style.top = parseInt(args.tooltip.style.top) + 10 + adjustment + 'px';
3844
+ }
3845
+ };
3846
+
3847
+
3848
+
3849
+
3850
+
3851
+
3852
+
3853
+
3854
+ //
3855
+ // This returns the relevant value for the formatted key
3856
+ // macro %{value}. THIS VALUE SHOULD NOT BE FORMATTED.
3857
+ //
3858
+ // @param number index The index in the dataset to get
3859
+ // the value for
3860
+ //
3861
+ this.getKeyValue = function (index)
3862
+ {
3863
+ if (RGraph.isArray(this.properties.keyFormattedValueSpecific) && RGraph.isNumber(this.properties.keyFormattedValueSpecific[index])) {
3864
+ return this.properties.keyFormattedValueSpecific[index];
3865
+
3866
+ } else {
3867
+
3868
+ var total = 0;
3869
+
3870
+ // LHS data
3871
+ for (let i=0; i<this.data[0].length; ++i) {
3872
+ if (RGraph.isArray(this.data[0][i])) {
3873
+ total += this.data[0][i][index];
3874
+ }
3875
+ }
3876
+
3877
+ // RHS data
3878
+ for (let i=0; i<this.data[1].length; ++i) {
3879
+ if (RGraph.isArray(this.data[1][i])) {
3880
+ total += this.data[1][i][index];
3881
+ }
3882
+ }
3883
+
3884
+ return total;
3885
+ }
3886
+ };
3887
+
3888
+
3889
+
3890
+
3891
+
3892
+
3893
+
3894
+
3895
+ //
3896
+ // Returns how many data-points there should be when a string
3897
+ // based key property has been specified. For example, this:
3898
+ //
3899
+ // key: '%{property:_labels[%{index}]} %{value_formatted}'
3900
+ //
3901
+ // ...depending on how many bits of data ther is might get
3902
+ // turned into this:
3903
+ //
3904
+ // key: [
3905
+ // '%{property:_labels[%{index}]} %{value_formatted}',
3906
+ // '%{property:_labels[%{index}]} %{value_formatted}',
3907
+ // '%{property:_labels[%{index}]} %{value_formatted}',
3908
+ // '%{property:_labels[%{index}]} %{value_formatted}',
3909
+ // '%{property:_labels[%{index}]} %{value_formatted}',
3910
+ // ]
3911
+ //
3912
+ // ... ie in that case there would be 4 data-points so the
3913
+ // template is repeated 4 times.
3914
+ //
3915
+ this.getKeyNumDatapoints = function ()
3916
+ {
3917
+ var num = 1;
3918
+
3919
+ for (let side=0; side<this.data.length; ++side) {
3920
+ for (let i=0; i<this.data[side].length; ++i) {
3921
+ if (RGraph.isArray(this.data[side][i])) {
3922
+ num = Math.max(
3923
+ num,
3924
+ this.data[side][i].length
3925
+ );
3926
+ }
3927
+ }
3928
+ }
3929
+
3930
+ return num;
3931
+ };
3932
+
3933
+
3934
+
3935
+
3936
+
3937
+
3938
+
3939
+
3940
+
3941
+ //
3942
+ // Objects are now always registered so that when RGraph.redraw()
3943
+ // is called this chart will be redrawn.
3944
+ //
3945
+ RGraph.register(this);
3946
+
3947
+
3948
+
3949
+
3950
+
3951
+
3952
+
3953
+
3954
+ //
3955
+ // This is the 'end' of the constructor so if the first argument
3956
+ // contains configuration dsta - handle that.
3957
+ //
3958
+ RGraph.parseObjectStyleConfig(this, conf.options);
3959
+ };