rgraph-rails 1.0.7 → 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/lib/rgraph-rails/version.rb +1 -1
  4. data/license.txt +4 -16
  5. data/vendor/assets/javascripts/RGraph.bar.js +3734 -241
  6. data/vendor/assets/javascripts/RGraph.bipolar.js +2005 -115
  7. data/vendor/assets/javascripts/RGraph.common.annotate.js +395 -35
  8. data/vendor/assets/javascripts/RGraph.common.context.js +595 -30
  9. data/vendor/assets/javascripts/RGraph.common.core.js +5282 -405
  10. data/vendor/assets/javascripts/RGraph.common.csv.js +276 -19
  11. data/vendor/assets/javascripts/RGraph.common.deprecated.js +450 -35
  12. data/vendor/assets/javascripts/RGraph.common.dynamic.js +1395 -86
  13. data/vendor/assets/javascripts/RGraph.common.effects.js +1545 -90
  14. data/vendor/assets/javascripts/RGraph.common.key.js +753 -54
  15. data/vendor/assets/javascripts/RGraph.common.resizing.js +563 -37
  16. data/vendor/assets/javascripts/RGraph.common.sheets.js +352 -29
  17. data/vendor/assets/javascripts/RGraph.common.tooltips.js +450 -32
  18. data/vendor/assets/javascripts/RGraph.common.zoom.js +219 -14
  19. data/vendor/assets/javascripts/RGraph.drawing.background.js +570 -35
  20. data/vendor/assets/javascripts/RGraph.drawing.circle.js +544 -35
  21. data/vendor/assets/javascripts/RGraph.drawing.image.js +755 -52
  22. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +645 -41
  23. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +633 -37
  24. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +514 -36
  25. data/vendor/assets/javascripts/RGraph.drawing.poly.js +559 -39
  26. data/vendor/assets/javascripts/RGraph.drawing.rect.js +548 -35
  27. data/vendor/assets/javascripts/RGraph.drawing.text.js +664 -36
  28. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +812 -50
  29. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +856 -51
  30. data/vendor/assets/javascripts/RGraph.fuel.js +964 -58
  31. data/vendor/assets/javascripts/RGraph.funnel.js +984 -55
  32. data/vendor/assets/javascripts/RGraph.gantt.js +1354 -77
  33. data/vendor/assets/javascripts/RGraph.gauge.js +1421 -87
  34. data/vendor/assets/javascripts/RGraph.hbar.js +2562 -146
  35. data/vendor/assets/javascripts/RGraph.hprogress.js +1401 -80
  36. data/vendor/assets/javascripts/RGraph.line.js +4226 -244
  37. data/vendor/assets/javascripts/RGraph.meter.js +1280 -74
  38. data/vendor/assets/javascripts/RGraph.modaldialog.js +301 -19
  39. data/vendor/assets/javascripts/RGraph.odo.js +1264 -71
  40. data/vendor/assets/javascripts/RGraph.pie.js +2288 -137
  41. data/vendor/assets/javascripts/RGraph.radar.js +1847 -110
  42. data/vendor/assets/javascripts/RGraph.rose.js +1977 -108
  43. data/vendor/assets/javascripts/RGraph.rscatter.js +1432 -80
  44. data/vendor/assets/javascripts/RGraph.scatter.js +3036 -168
  45. data/vendor/assets/javascripts/RGraph.semicircularprogress.js +1120 -60
  46. data/vendor/assets/javascripts/RGraph.svg.bar.js +1067 -0
  47. data/vendor/assets/javascripts/RGraph.svg.common.ajax.js +247 -0
  48. data/vendor/assets/javascripts/RGraph.svg.common.core.js +3363 -0
  49. data/vendor/assets/javascripts/RGraph.svg.common.csv.js +277 -0
  50. data/vendor/assets/javascripts/RGraph.svg.common.fx.js +1304 -0
  51. data/vendor/assets/javascripts/RGraph.svg.common.sheets.js +353 -0
  52. data/vendor/assets/javascripts/RGraph.svg.common.tooltips.js +233 -0
  53. data/vendor/assets/javascripts/RGraph.svg.hbar.js +1141 -0
  54. data/vendor/assets/javascripts/RGraph.svg.line.js +1486 -0
  55. data/vendor/assets/javascripts/RGraph.svg.pie.js +781 -0
  56. data/vendor/assets/javascripts/RGraph.svg.radar.js +1326 -0
  57. data/vendor/assets/javascripts/RGraph.svg.semicircularprogress.js +817 -0
  58. data/vendor/assets/javascripts/RGraph.thermometer.js +1135 -62
  59. data/vendor/assets/javascripts/RGraph.vprogress.js +1470 -83
  60. data/vendor/assets/javascripts/RGraph.waterfall.js +1347 -80
  61. metadata +15 -3
@@ -1,147 +1,2563 @@
1
+ // version: 2017-01-02
2
+ /**
3
+ * o--------------------------------------------------------------------------------o
4
+ * | This file is part of the RGraph package - you can learn more at: |
5
+ * | |
6
+ * | http://www.rgraph.net |
7
+ * | |
8
+ * | RGraph is licensed under the Open Source MIT license. That means that it's |
9
+ * | totally free to use! |
10
+ * o--------------------------------------------------------------------------------o
11
+ */
1
12
 
2
- RGraph=window.RGraph||{isRGraph:true};RGraph.HBar=function(conf)
3
- {if(typeof conf==='object'&&typeof conf.data==='object'&&typeof conf.id==='string'){var id=conf.id
4
- var canvas=document.getElementById(id);var data=conf.data;var parseConfObjectForOptions=true;}else{var id=conf;var canvas=document.getElementById(id);var data=arguments[1];}
5
- this.id=id;this.canvas=canvas;this.context=this.canvas.getContext?this.canvas.getContext("2d",{alpha:(typeof id==='object'&&id.alpha===false)?false:true}):null;this.canvas.__object__=this;this.data=data;this.type='hbar';this.isRGraph=true;this.uid=RGraph.CreateUID();this.canvas.uid=this.canvas.uid?this.canvas.uid:RGraph.CreateUID();this.colorsParsed=false;this.coords=[];this.coords2=[];this.coordsText=[];this.original_colors=[];this.firstDraw=true;this.max=0;this.stackedOrGrouped=false;this.properties={'chart.gutter.left':75,'chart.gutter.left.autosize':false,'chart.gutter.right':25,'chart.gutter.top':25,'chart.gutter.bottom':25,'chart.background.grid':true,'chart.background.grid.color':'#ddd','chart.background.grid.width':1,'chart.background.grid.hsize':25,'chart.background.grid.vsize':25,'chart.background.barcolor1':'rgba(0,0,0,0)','chart.background.barcolor2':'rgba(0,0,0,0)','chart.background.grid.hlines':true,'chart.background.grid.vlines':true,'chart.background.grid.border':true,'chart.background.grid.autofit':true,'chart.background.grid.autofit.align':true,'chart.background.grid.autofit.numhlines':null,'chart.background.grid.autofit.numvlines':5,'chart.background.grid.dashed':false,'chart.background.grid.dotted':false,'chart.background.color':null,'chart.linewidth':1,'chart.title':'','chart.title.background':null,'chart.title.xaxis':'','chart.title.xaxis.bold':true,'chart.title.xaxis.size':null,'chart.title.xaxis.font':null,'chart.title.yaxis':'','chart.title.yaxis.bold':true,'chart.title.yaxis.size':null,'chart.title.yaxis.font':null,'chart.title.yaxis.color':null,'chart.title.xaxis.pos':null,'chart.title.yaxis.pos':0.8,'chart.title.yaxis.x':null,'chart.title.yaxis.y':null,'chart.title.xaxis.x':null,'chart.title.xaxis.y':null,'chart.title.xaxis.color':null,'chart.title.hpos':null,'chart.title.vpos':null,'chart.title.bold':true,'chart.title.font':null,'chart.title.x':null,'chart.title.y':null,'chart.title.halign':null,'chart.title.valign':null,'chart.text.size':12,'chart.text.color':'black','chart.text.font':'Segoe UI, Arial, Verdana, sans-serif','chart.text.accessible':true,'chart.text.accessible.overflow':'visible','chart.text.accessible.pointerevents':true,'chart.colors':['red','blue','green','pink','yellow','cyan','navy','gray','black'],'chart.colors.sequential':false,'chart.xlabels.specific':null,'chart.labels':[],'chart.labels.bold':false,'chart.labels.color':null,'chart.labels.above':false,'chart.labels.above.decimals':0,'chart.labels.above.specific':null,'chart.labels.above.color':null,'chart.labels.above.units.pre':'','chart.labels.above.units.post':'','chart.labels.above.font':null,'chart.labels.above.size':null,'chart.labels.above.bold':false,'chart.labels.above.italic':false,'chart.labels.offsetx':0,'chart.labels.offsety':0,'chart.xlabels.offsetx':0,'chart.xlabels.offsety':0,'chart.xlabels':true,'chart.xlabels.count':5,'chart.contextmenu':null,'chart.key':null,'chart.key.background':'white','chart.key.position':'graph','chart.key.halign':'right','chart.key.shadow':false,'chart.key.shadow.color':'#666','chart.key.shadow.blur':3,'chart.key.shadow.offsetx':2,'chart.key.shadow.offsety':2,'chart.key.position.gutter.boxed':false,'chart.key.position.x':null,'chart.key.position.y':null,'chart.key.color.shape':'square','chart.key.rounded':true,'chart.key.linewidth':1,'chart.key.colors':null,'chart.key.interactive':false,'chart.key.interactive.highlight.chart.stroke':'black','chart.key.interactive.highlight.chart.fill':'rgba(255,255,255,0.7)','chart.key.interactive.highlight.label':'rgba(255,0,0,0.2)','chart.key.text.color':'black','chart.units.pre':'','chart.units.post':'','chart.units.ingraph':false,'chart.strokestyle':'rgba(0,0,0,0)','chart.xmin':0,'chart.xmax':0,'chart.axis.color':'black','chart.shadow':false,'chart.shadow.color':'#666','chart.shadow.blur':3,'chart.shadow.offsetx':3,'chart.shadow.offsety':3,'chart.vmargin':2,'chart.vmargin.grouped':2,'chart.grouping':'grouped','chart.tooltips':null,'chart.tooltips.event':'onclick','chart.tooltips.effect':'fade','chart.tooltips.css.class':'RGraph_tooltip','chart.tooltips.highlight':true,'chart.highlight.fill':'rgba(255,255,255,0.7)','chart.highlight.stroke':'rgba(0,0,0,0)','chart.highlight.style':null,'chart.annotatable':false,'chart.annotate.color':'black','chart.zoom.factor':1.5,'chart.zoom.fade.in':true,'chart.zoom.fade.out':true,'chart.zoom.hdir':'right','chart.zoom.vdir':'down','chart.zoom.frames':25,'chart.zoom.delay':16.666,'chart.zoom.shadow':true,'chart.zoom.background':true,'chart.zoom.action':'zoom','chart.resizable':false,'chart.resize.handle.adjust':[0,0],'chart.resize.handle.background':null,'chart.scale.point':'.','chart.scale.thousand':',','chart.scale.decimals':null,'chart.scale.zerostart':true,'chart.noredraw':false,'chart.events.click':null,'chart.events.mousemove':null,'chart.noxaxis':false,'chart.noyaxis':false,'chart.noaxes':false,'chart.noxtickmarks':false,'chart.noytickmarks':false,'chart.numyticks':data.length,'chart.numxticks':10,'chart.variant':'hbar','chart.variant.threed.angle':0.1,'chart.variant.threed.offsetx':10,'chart.variant.threed.offsety':5,'chart.variant.threed.xaxis':true,'chart.variant.threed.yaxis':true,'chart.yaxispos':'left','chart.variant':'hbar','chart.clearto':'rgba(0,0,0,0)','chart.adjustable':false,'chart.adjustable.only':null}
6
- if(!this.canvas){alert('[HBAR] No canvas support');return;}
7
- for(i=0,len=this.data.length;i<len;++i){if(typeof this.data[i]=='object'&&!RGraph.isNull(this.data[i])){this.stackedOrGrouped=true;for(var j=0,len2=this.data[i].length;j<len2;++j){if(typeof this.data[i][j]==='string'){this.data[i][j]=parseFloat(this.data[i][j]);}}}else if(typeof this.data[i]=='string'){this.data[i]=parseFloat(this.data[i])||0;}else if(typeof this.data[i]==='undefined'){this.data[i]=null;}}
8
- var linear_data=RGraph.arrayLinearize(data);for(var i=0,len=linear_data.length;i<len;++i){this['$'+i]={};}
9
- this.data_arr=RGraph.arrayLinearize(this.data);if(!this.canvas.__rgraph_aa_translated__){this.context.translate(0.5,0.5);this.canvas.__rgraph_aa_translated__=true;}
10
- var RG=RGraph,ca=this.canvas,co=ca.getContext('2d'),prop=this.properties,pa2=RG.path2,win=window,doc=document,ma=Math
11
- if(RG.Effects&&typeof RG.Effects.decorate==='function'){RG.Effects.decorate(this);}
12
- this.set=this.Set=function(name)
13
- {var value=typeof arguments[1]==='undefined'?null:arguments[1];if(arguments.length===1&&typeof name==='object'){RG.parseObjectStyleConfig(this,name);return this;}
14
- if(name.substr(0,6)!='chart.'){name='chart.'+name;}
15
- while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
16
- if(name=='chart.labels.abovebar'){name='chart.labels.above';}
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
- if(name=='chart.labels.abovebar'){name='chart.labels.above';}
21
- return prop[name];};this.draw=this.Draw=function()
22
- {RG.fireCustomEvent(this,'onbeforedraw');if(prop['chart.adjustable']&&prop['chart.grouping']==='stacked'){alert('[RGRAPH] The HBar does not support stacked charts with adjusting');}
23
- 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
- if(prop['chart.gutter.bottom']===25){this.set('gutterBottom',80);}}
25
- if(!this.colorsParsed){this.parseColors();this.colorsParsed=true;}
26
- if(prop['chart.gutter.left.autosize']){var len=0;var labels=prop['chart.labels'];var font=prop['chart.text.font'];var size=prop['chart.text.size'];for(var i=0;i<labels.length;i+=1){var length=RG.measureText(labels[i],false,font,size)[0]||0
27
- len=ma.max(len,length);}
28
- prop['chart.gutter.left']=len+10;}
29
- this.gutterLeft=prop['chart.gutter.left'];this.gutterRight=prop['chart.gutter.right'];this.gutterTop=prop['chart.gutter.top'];this.gutterBottom=prop['chart.gutter.bottom'];this.coords=[];this.coords2=[];this.coordsText=[];this.max=0;if(prop['chart.xmin']>0&&prop['chart.grouping']=='stacked'){alert('[HBAR] Using chart.xmin is not supported with stacked charts, resetting chart.xmin to zero');this.Set('chart.xmin',0);}
30
- this.graphwidth=ca.width-this.gutterLeft-this.gutterRight;this.graphheight=ca.height-this.gutterTop-this.gutterBottom;this.halfgrapharea=this.grapharea/2;this.halfTextHeight=prop['chart.text.size']/2;this.halfway=ma.round((this.graphwidth/2)+this.gutterLeft)
31
- RG.Background.draw(this);this.drawbars();this.drawAxes();this.drawLabels();if(prop['chart.key']&&prop['chart.key'].length){RG.DrawKey(this,prop['chart.key'],prop['chart.colors']);}
32
- if(prop['chart.contextmenu']){RG.ShowContext(this);}
33
- RG.DrawInGraphLabels(this);if(prop['chart.resizable']){RG.AllowResizing(this);}
34
- RG.InstallEventListeners(this);if(this.firstDraw){RG.fireCustomEvent(this,'onfirstdraw');this.firstDraw=false;this.firstDrawFunc();}
35
- RG.FireCustomEvent(this,'ondraw');return this;};this.exec=function(func)
36
- {func(this);return this;};this.drawAxes=this.DrawAxes=function()
37
- {var halfway=this.halfway
38
- co.beginPath();co.lineWidth=prop['chart.axis.linewidth']?prop['chart.axis.linewidth']+0.001:1.001;co.strokeStyle=prop['chart.axis.color'];if(prop['chart.noyaxis']==false&&prop['chart.noaxes']==false){if(prop['chart.yaxispos']=='center'){co.moveTo(halfway,this.gutterTop);co.lineTo(halfway,ca.height-this.gutterBottom);}else if(prop['chart.yaxispos']=='right'){co.moveTo(ca.width-this.gutterRight,this.gutterTop);co.lineTo(ca.width-this.gutterRight,ca.height-this.gutterBottom);}else{co.moveTo(this.gutterLeft,this.gutterTop);co.lineTo(this.gutterLeft,ca.height-this.gutterBottom);}}
39
- if(prop['chart.noxaxis']==false&&prop['chart.noaxes']==false){co.moveTo(this.gutterLeft+0.001,ca.height-this.gutterBottom+0.001);co.lineTo(ca.width-this.gutterRight+0.001,ca.height-this.gutterBottom+0.001);}
40
- if(prop['chart.noytickmarks']==false&&prop['chart.noyaxis']==false&&prop['chart.numyticks']>0&&prop['chart.noaxes']==false){var yTickGap=(ca.height-this.gutterTop-this.gutterBottom)/(prop['chart.numyticks']>0?prop['chart.numyticks']:this.data.length);for(y=this.gutterTop;y<(ca.height-this.gutterBottom-1);y+=yTickGap){if(prop['chart.yaxispos']=='center'){co.moveTo(halfway+3,ma.round(y));co.lineTo(halfway-3,ma.round(y));}else if(prop['chart.yaxispos']=='right'){co.moveTo(ca.width-this.gutterRight,ma.round(y));co.lineTo(ca.width-this.gutterRight+3,ma.round(y));}else{co.moveTo(this.gutterLeft,ma.round(y));co.lineTo(this.gutterLeft-3,ma.round(y));}}
41
- if(prop['chart.noxaxis']==true){if(prop['chart.yaxispos']=='center'){co.moveTo(halfway+3,ma.round(y));co.lineTo(halfway-3,ma.round(y));}else if(prop['chart.yaxispos']=='right'){co.moveTo(ca.width-this.gutterRight,ma.round(y));co.lineTo(ca.width-this.gutterRight+3,ma.round(y));}else{co.moveTo(this.gutterLeft,ma.round(y));co.lineTo(this.gutterLeft-3,ma.round(y));}}}
42
- if(prop['chart.noxtickmarks']==false&&prop['chart.noxaxis']==false&&prop['chart.numxticks']>0&&prop['chart.noaxes']==false){xTickGap=(ca.width-this.gutterLeft-this.gutterRight)/prop['chart.numxticks'];yStart=ca.height-this.gutterBottom;yEnd=(ca.height-this.gutterBottom)+3;var i=prop['chart.numxticks']
43
- while(i--){var x=ca.width-this.gutterRight-(i*xTickGap);if(prop['chart.yaxispos']==='right'){x-=xTickGap;}
44
- co.moveTo(ma.round(x),yStart);co.lineTo(ma.round(x),yEnd);}
45
- if(prop['chart.yaxispos']==='center'){var i=5;while(i--){var x=this.gutterLeft+(xTickGap*i);co.moveTo(ma.round(x),yStart);co.lineTo(ma.round(x),yEnd);}}
46
- if(prop['chart.noyaxis']==true){co.moveTo(this.gutterLeft,ma.round(yStart));co.lineTo(this.gutterLeft,ma.round(yEnd));}}
47
- co.stroke();co.lineWidth=1;};this.drawLabels=this.DrawLabels=function()
48
- {var units_pre=prop['chart.units.pre'],units_post=prop['chart.units.post'],text_size=prop['chart.text.size'],font=prop['chart.text.font'],offsetx=prop['chart.xlabels.offsetx'],offsety=prop['chart.xlabels.offsety']
49
- if(prop['chart.units.ingraph']){units_pre='';units_post='';}
50
- if(prop['chart.xlabels']){if(RG.isArray(prop['chart.xlabels.specific'])){if(prop['chart.yaxispos']=='center'){var halfGraphWidth=this.graphwidth/2;var labels=prop['chart.xlabels.specific'];var interval=(this.graphwidth/2)/(labels.length-1);co.fillStyle=prop['chart.text.color'];for(var i=0;i<labels.length;i+=1){RG.text2(this,{'font':font,'size':text_size,'x':this.gutterLeft+halfGraphWidth+(interval*i)+offsetx,'y':ca.height-this.gutterBottom+offsetx,'text':labels[i],'valign':'top','halign':'center','tag':'scale'});}
51
- for(var i=(labels.length-1);i>0;i-=1){RG.Text2(this,{'font':font,'size':text_size,'x':this.gutterLeft+(interval*(labels.length-i-1))+offsetx,'y':ca.height-this.gutterBottom+offsety,'text':labels[i],'valign':'top','halign':'center','tag':'scale'});}}else if(prop['chart.yaxispos']=='right'){var labels=prop['chart.xlabels.specific'];var interval=this.graphwidth/(labels.length-1);co.fillStyle=prop['chart.text.color'];for(var i=0;i<labels.length;i+=1){RG.text2(this,{'font':font,'size':text_size,'x':this.gutterLeft+(interval*i)+offsetx,'y':ca.height-this.gutterBottom+offsety,'text':labels[labels.length-i-1],'valign':'top','halign':'center','tag':'scale'});}}else{var labels=prop['chart.xlabels.specific'];var interval=this.graphwidth/(labels.length-1);co.fillStyle=prop['chart.text.color'];for(var i=0;i<labels.length;i+=1){RG.text2(this,{font:font,size:text_size,x:this.gutterLeft+(interval*i)+offsetx,y:ca.height-this.gutterBottom+offsety,text:labels[i],valign:'top',halign:'center',tag:'scale'});}}}else{var gap=7;co.beginPath();co.fillStyle=prop['chart.text.color'];if(prop['chart.yaxispos']=='center'){for(var i=0;i<this.scale2.labels.length;++i){RG.text2(this,{'font':font,'size':text_size,'x':this.gutterLeft+(this.graphwidth/2)-((this.graphwidth/2)*((i+1)/this.scale2.labels.length))+offsetx,'y':this.gutterTop+this.halfTextHeight+this.graphheight+gap+offsety,'text':'-'+this.scale2.labels[i],'valign':'center','halign':'center','tag':'scale'});}
52
- for(var i=0;i<this.scale2.labels.length;++i){RG.text2(this,{'font':font,'size':text_size,'x':this.gutterLeft+((this.graphwidth/2)*((i+1)/this.scale2.labels.length))+(this.graphwidth/2)+offsetx,'y':this.gutterTop+this.halfTextHeight+this.graphheight+gap+offsety,'text':this.scale2.labels[i],'valign':'center','halign':'center','tag':'scale'});}}else if(prop['chart.yaxispos']=='right'){for(var i=0,len=this.scale2.labels.length;i<len;++i){RG.Text2(this,{'font':font,'size':text_size,'x':this.gutterLeft+(i*(this.graphwidth/len))+offsetx,'y':this.gutterTop+this.halfTextHeight+this.graphheight+gap+offsety,'text':'-'+this.scale2.labels[len-1-i],'valign':'center','halign':'center','tag':'scale'});}}else{for(var i=0,len=this.scale2.labels.length;i<len;++i){RG.Text2(this,{'font':font,'size':text_size,'x':this.gutterLeft+(this.graphwidth*((i+1)/len))+offsetx,'y':this.gutterTop+this.halfTextHeight+this.graphheight+gap+offsety,'text':this.scale2.labels[i],'valign':'center','halign':'center','tag':'scale'});}}
53
- if(prop['chart.xmin']>0||prop['chart.noyaxis']==true||prop['chart.scale.zerostart']||prop['chart.noaxes']){var x=prop['chart.yaxispos']=='center'?this.gutterLeft+(this.graphwidth/2):this.gutterLeft;if(prop['chart.yaxispos']==='right'){var x=ca.width-this.gutterRight;}
54
- RG.text2(this,{'font':font,'size':text_size,'x':x+offsetx,'y':this.gutterTop+this.halfTextHeight+this.graphheight+gap+offsety,'text':RG.numberFormat(this,prop['chart.xmin'].toFixed(prop['chart.xmin']===0?0:prop['chart.scale.decimals']),units_pre,units_post),'valign':'center','halign':'center','tag':'scale'});}
55
- co.fill();co.stroke();}}
56
- if(typeof prop['chart.labels']=='object'){var xOffset=prop['chart.variant']==='3d'&&prop['chart.yaxispos']==='right'?15:5,font=prop['chart.text.font'],color=prop['chart.labels.color']||prop['chart.text.color'],bold=prop['chart.labels.bold'],offsetx=prop['chart.labels.offsetx'],offsety=prop['chart.labels.offsety']
57
- co.fillStyle=color;var barHeight=(ca.height-this.gutterTop-this.gutterBottom)/prop['chart.labels'].length;yTickGap=(ca.height-this.gutterTop-this.gutterBottom)/prop['chart.labels'].length
58
- if(prop['chart.yaxispos']==='right'){var x=ca.width-this.gutterRight+xOffset;var halign='left'}else{var x=this.gutterLeft-xOffset;var halign='right'}
59
- var i=0;for(y=this.gutterTop+(yTickGap/2);y<=ca.height-this.gutterBottom;y+=yTickGap){RG.text2(this,{'font':font,'size':prop['chart.text.size'],'bold':bold,'x':x+offsetx,'y':y+offsety,'text':String(prop['chart.labels'][i++]),'halign':halign,'valign':'center','tag':'labels'});}}};this.drawbars=this.Drawbars=function()
60
- {co.lineWidth=prop['chart.linewidth'];co.strokeStyle=prop['chart.strokestyle'];co.fillStyle=prop['chart.colors'][0];var prevX=0,prevY=0;if(prop['chart.xmax']){this.scale2=RG.getScale2(this,{'max':prop['chart.xmax'],'min':prop['chart.xmin'],'scale.decimals':Number(prop['chart.scale.decimals']),'scale.point':prop['chart.scale.point'],'scale.thousand':prop['chart.scale.thousand'],'scale.round':prop['chart.scale.round'],'units.pre':prop['chart.units.pre'],'units.post':prop['chart.units.post'],'ylabels.count':prop['chart.xlabels.count'],'strict':true});this.max=this.scale2.max;}else{var grouping=prop['chart.grouping'];for(i=0;i<this.data.length;++i){if(typeof(this.data[i])=='object'){var value=grouping=='grouped'?Number(RG.array_max(this.data[i],true)):Number(RG.array_sum(this.data[i]));}else{var value=Number(ma.abs(this.data[i]));}
61
- this.max=ma.max(Math.abs(this.max),Math.abs(value));}
62
- this.scale2=RG.getScale2(this,{'max':this.max,'min':prop['chart.xmin'],'scale.decimals':Number(prop['chart.scale.decimals']),'scale.point':prop['chart.scale.point'],'scale.thousand':prop['chart.scale.thousand'],'scale.round':prop['chart.scale.round'],'units.pre':prop['chart.units.pre'],'units.post':prop['chart.units.post'],'ylabels.count':prop['chart.xlabels.count']});this.max=this.scale2.max;this.min=this.scale2.min;}
63
- if(prop['chart.scale.decimals']==null&&Number(this.max)==1){this.Set('chart.scale.decimals',1);}
64
- var colorIdx=0;this.numbars=RG.arrayLinearize(this.data).length;if(prop['chart.adjustable']&&!prop['chart.xmax']){this.set('chart.xmax',this.scale2.max);}
65
- if(prop['chart.variant']==='3d'){RG.draw3DAxes(this);}
66
- var graphwidth=(ca.width-this.gutterLeft-this.gutterRight);var halfwidth=graphwidth/2;for(i=(len=this.data.length-1);i>=0;--i){var width=ma.abs((this.data[i]/this.max)*graphwidth);var height=this.graphheight/this.data.length;var orig_height=height;var x=this.gutterLeft;var y=this.gutterTop+(i*height);var vmargin=prop['chart.vmargin'];if(prop['chart.yaxispos']==='right'){x=ca.width-this.gutterRight-ma.abs(width);}
67
- if(width<0){x-=width;width=ma.abs(width);}
68
- if(prop['chart.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'];}
69
- co.beginPath();if(typeof this.data[i]=='number'||RG.isNull(this.data[i])){var barHeight=height-(2*vmargin),barWidth=((this.data[i]-prop['chart.xmin'])/(this.max-prop['chart.xmin']))*this.graphwidth,barX=this.gutterLeft;if(prop['chart.yaxispos']=='center'){barWidth/=2;barX+=halfwidth;if(this.data[i]<0){barWidth=(ma.abs(this.data[i])-prop['chart.xmin'])/(this.max-prop['chart.xmin']);barWidth=barWidth*(this.graphwidth/2);barX=((this.graphwidth/2)+this.gutterLeft)-barWidth;}}else if(prop['chart.yaxispos']=='right'){barWidth=ma.abs(barWidth);barX=ca.width-this.gutterRight-barWidth;}
70
- co.strokeStyle=prop['chart.strokestyle'];co.fillStyle=prop['chart.colors'][0];++colorIdx;if(prop['chart.colors.sequential']&&typeof colorIdx==='number'){if(prop['chart.colors'][this.numbars-colorIdx]){co.fillStyle=prop['chart.colors'][this.numbars-colorIdx];}else{co.fillStyle=prop['chart.colors'][prop['chart.colors'].length-1];}}
71
- co.strokeRect(barX,this.gutterTop+(i*height)+prop['chart.vmargin'],barWidth,barHeight);co.fillRect(barX,this.gutterTop+(i*height)+prop['chart.vmargin'],barWidth,barHeight);this.coords.push([barX,y+vmargin,barWidth,height-(2*vmargin),co.fillStyle,this.data[i],true]);if(prop['chart.variant']==='3d'&&typeof this.data[i]=='number'){var prevStrokeStyle=co.strokeStyle,prevFillStyle=co.fillStyle;RG.noShadow(this);var barX=barX,barY=y+vmargin,barW=barWidth,barH=height-(2*vmargin),offsetX=prop['chart.variant.threed.offsetx'],offsetY=prop['chart.variant.threed.offsety'],value=this.data[i];pa2(co,['b','m',barX,barY,'l',barX+offsetX-(prop['chart.yaxispos']=='left'&&value<0?offsetX:0),barY-offsetY,'l',barX+barW+offsetX-(prop['chart.yaxispos']=='center'&&value<0?offsetX:0),barY-offsetY,'l',barX+barW,barY,'c','s',co.strokeStyle,'f',co.fillStyle,'f','rgba(255,255,255,0.6)']);if(prop['chart.yaxispos']!=='right'&&!(prop['chart.yaxispos']==='center'&&value<0)&&value>=0&&!RG.isNull(value)){pa2(co,['b','fs',prevFillStyle,'m',barX+barW,barY,'l',barX+barW+offsetX,barY-offsetY,'l',barX+barW+offsetX,barY-offsetY+barH,'l',barX+barW,barY+barH,'c','s',co.strokeStyle,'f',prevFillStyle,'f','rgba(0,0,0,0.25)']);}}}else if(typeof(this.data[i])=='object'&&prop['chart.grouping']=='stacked'){if(prop['chart.yaxispos']=='center'){alert('[HBAR] You can\'t have a stacked chart with the Y axis in the center, change it to grouped');}else if(prop['chart.yaxispos']=='right'){var x=ca.width-this.gutterRight}
72
- var barHeight=height-(2*vmargin);if(typeof this.coords2[i]=='undefined'){this.coords2[i]=[];}
73
- for(j=0;j<this.data[i].length;++j){if(prop['chart.shadow']&&prop['chart.variant']==='3d'){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];}
74
- if(!RG.isNull(this.data[i][j]))this.data[i][j]=ma.abs(this.data[i][j]);var last=(j===(this.data[i].length-1));co.strokeStyle=prop['chart.strokestyle'];++colorIdx;if(prop['chart.colors.sequential']&&typeof colorIdx==='number'){if(prop['chart.colors'][this.numbars-colorIdx]){co.fillStyle=prop['chart.colors'][this.numbars-colorIdx];}else{co.fillStyle=prop['chart.colors'][prop['chart.colors'].length-1];}}else if(prop['chart.colors'][j]){co.fillStyle=prop['chart.colors'][j];}
75
- var width=(((this.data[i][j])/(this.max)))*this.graphwidth;var totalWidth=(RG.arraySum(this.data[i])/this.max)*this.graphwidth;if(prop['chart.yaxispos']==='right'){x-=width;}
76
- co.strokeRect(x,this.gutterTop+prop['chart.vmargin']+(this.graphheight/this.data.length)*i,width,height-(2*vmargin));co.fillRect(x,this.gutterTop+prop['chart.vmargin']+(this.graphheight/this.data.length)*i,width,height-(2*vmargin));this.coords.push([x,y+vmargin,width,height-(2*vmargin),co.fillStyle,RG.array_sum(this.data[i]),j==(this.data[i].length-1)]);this.coords2[i].push([x,y+vmargin,width,height-(2*vmargin),co.fillStyle,RG.array_sum(this.data[i]),j==(this.data[i].length-1)]);if(prop['chart.variant']==='3d'){RG.noShadow(this);var prevStrokeStyle=co.strokeStyle,prevFillStyle=co.fillStyle;var barX=x,barY=y+vmargin,barW=width,barH=height-(2*vmargin),offsetX=prop['chart.variant.threed.offsetx'],offsetY=prop['chart.variant.threed.offsety'],value=this.data[i][j];if(!RG.isNull(value)){pa2(co,['b','m',barX,barY,'l',barX+offsetX,barY-offsetY,'l',barX+barW+offsetX,barY-offsetY,'l',barX+barW,barY,'c','s',co.strokeStyle,'f',co.fillStyle,'f','rgba(255,255,255,0.6)']);}
77
- if(prop['chart.yaxispos']!=='right'&&!(prop['chart.yaxispos']==='center'&&value<0)&&!RG.isNull(value)){pa2(co,['fs',prevFillStyle,'b','m',barX+barW,barY,'l',barX+barW+offsetX,barY-offsetY,'l',barX+barW+offsetX,barY-offsetY+barH,'l',barX+barW,barY+barH,'c','s',co.strokeStyle,'f',prevFillStyle,'f','rgba(0,0,0,0.25)']);}
78
- co.beginPath();co.strokeStyle=prevStrokeStyle;co.fillStyle=prevFillStyle;}
79
- if(prop['chart.yaxispos']!=='right'){x+=width;}}}else if(typeof(this.data[i])=='object'&&prop['chart.grouping']=='grouped'){var vmarginGrouped=prop['chart.vmargin.grouped'];var individualBarHeight=((height-(2*vmargin)-((this.data[i].length-1)*vmarginGrouped))/this.data[i].length)
80
- if(typeof this.coords2[i]=='undefined'){this.coords2[i]=[];}
81
- for(j=(this.data[i].length-1);j>=0;--j){if(prop['chart.shadow']){RG.setShadow(this,prop['chart.shadow.color'],prop['chart.shadow.offsetx'],prop['chart.shadow.offsety'],prop['chart.shadow.blur']);}
82
- co.strokeStyle=prop['chart.strokestyle'];++colorIdx;if(prop['chart.colors.sequential']&&typeof colorIdx==='number'){if(prop['chart.colors'][this.numbars-colorIdx]){co.fillStyle=prop['chart.colors'][this.numbars-colorIdx];}else{co.fillStyle=prop['chart.colors'][prop['chart.colors'].length-1];}}else if(prop['chart.colors'][j]){co.fillStyle=prop['chart.colors'][j];}
83
- var startY=this.gutterTop+(height*i)+(individualBarHeight*j)+vmargin+(vmarginGrouped*j);var width=((this.data[i][j]-prop['chart.xmin'])/(this.max-prop['chart.xmin']))*(ca.width-this.gutterLeft-this.gutterRight);var startX=this.gutterLeft;if(prop['chart.yaxispos']=='center'){width/=2;startX+=halfwidth;}else if(prop['chart.yaxispos']=='right'){width=ma.abs(width);startX=ca.width-this.gutterRight-ma.abs(width);;}
84
- if(width<0){startX+=width;width*=-1;}
85
- co.strokeRect(startX,startY,width,individualBarHeight);co.fillRect(startX,startY,width,individualBarHeight);this.coords.push([startX,startY,width,individualBarHeight,co.fillStyle,this.data[i][j],true]);this.coords2[i].push([startX,startY,width,individualBarHeight,co.fillStyle,this.data[i][j],true]);if(prop['chart.variant']==='3d'){RG.noShadow(this);var prevStrokeStyle=co.strokeStyle,prevFillStyle=co.fillStyle;var barX=startX,barY=startY,barW=width,barH=individualBarHeight,offsetX=prop['chart.variant.threed.offsetx'],offsetY=prop['chart.variant.threed.offsety'],value=this.data[i][j];pa2(co,['b','m',barX,barY,'l',barX+offsetX,barY-offsetY,'l',barX+barW+offsetX-(value<0?offsetX:0),barY-offsetY,'l',barX+barW,barY,'c','s',co.strokeStyle,'f',co.fillStyle,'f','rgba(255,255,255,0.6)']);if(prop['chart.yaxispos']!=='right'&&!(prop['chart.yaxispos']==='center'&&value<0)&&value>=0&&!RG.isNull(value)){pa2(co,['fs',prevFillStyle,'b','m',barX+barW,barY,'l',barX+barW+offsetX,barY-offsetY,'l',barX+barW+offsetX,barY-offsetY+barH,'l',barX+barW,barY+barH,'c','s',co.strokeStyle,'f',prevFillStyle,'f','rgba(0,0,0,0.25)']);}
86
- co.beginPath();co.strokeStyle=prevStrokeStyle;co.fillStyle=prevFillStyle;}}
87
- startY+=vmargin;}
88
- co.closePath();}
89
- co.stroke();co.fill();if(prop['chart,yaxispos']==='right'){pa2(co,'cr % % % %',ca.width-this.gutterRight+prop['chart.variant.threed.offsetx'],'0',this.gutterRight,ca.height);}
90
- if(prop['chart.yaxispos']==='right'&&prop['chart.variant']==='3d'){RG.draw3DYAxis(this);}
91
- RG.noShadow(this);this.coords=RG.arrayReverse(this.coords);if(prop['chart.grouping']==='grouped'){for(var i=0;i<this.coords2.length;++i){this.coords2[i]=RG.arrayReverse(this.coords2[i]);}}
92
- this.redrawBars();};this.redrawBars=this.RedrawBars=function()
93
- {if(prop['chart.noredraw']){return;}
94
- var coords=this.coords;var font=prop['chart.text.font'],size=prop['chart.text.size'],color=prop['chart.text.color'];RG.noShadow(this);co.strokeStyle=prop['chart.strokestyle'];for(var i=0;i<coords.length;++i){if(prop['chart.shadow']){pa2(co,'b lw % r % % % % s % f %',prop['chart.linewidth'],coords[i][0],coords[i][1],coords[i][2],coords[i][3],prop['chart.strokestyle'],coords[i][4]);}
95
- var halign='left';if(prop['chart.labels.above']&&coords[i][6]){var border=(coords[i][0]+coords[i][2]+7+co.measureText(prop['chart.labels.above.units.pre']+this.coords[i][5]+prop['chart.labels.above.units.post']).width)>ca.width?true:false,text=RG.numberFormat(this,(this.coords[i][5]).toFixed(prop['chart.labels.above.decimals']),prop['chart.labels.above.units.pre'],prop['chart.labels.above.units.post']);RG.noShadow(this);if(typeof prop['chart.labels.above.specific']==='object'&&prop['chart.labels.above.specific']&&prop['chart.labels.above.specific'][i]){text=prop['chart.labels.above.specific'][i];}
96
- var x=coords[i][0]+coords[i][2]+5;var y=coords[i][1]+(coords[i][3]/2);if(prop['chart.yaxispos']==='right'){x=coords[i][0]-5;halign='right';}else if(prop['chart.yaxispos']==='center'&&this.data_arr[i]<0){x=coords[i][0]-5;halign='right';}
97
- RG.text2(this,{font:typeof prop['chart.labels.above.font']==='string'?prop['chart.labels.above.font']:font,size:typeof prop['chart.labels.above.size']==='number'?prop['chart.labels.above.size']:size,color:typeof prop['chart.labels.above.color']==='string'?prop['chart.labels.above.color']:color,x:x,y:y,bold:prop['chart.labels.above.bold'],italic:prop['chart.labels.above.italic'],text:text,valign:'center',halign:halign,tag:'labels.above'});}}};this.getShape=this.getBar=function(e)
98
- {var mouseXY=RG.getMouseXY(e);for(var i=0,len=this.coords.length;i<len;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],idx=i;pa2(co,['b','r',left,top,width,height]);if(co.isPointInPath(mouseX,mouseY)){var tooltip=RG.parseTooltipText(prop['chart.tooltips'],i);return{0:this,'object':this,1:left,'x':left,2:top,'y':top,3:width,'width':width,4:height,'height':height,5:idx,'index':idx,'tooltip':tooltip};}}};this.getValue=function(arg)
99
- {if(arg.length==2){var mouseX=arg[0];var mouseY=arg[1];}else{var mouseCoords=RG.getMouseXY(arg);var mouseX=mouseCoords[0];var mouseY=mouseCoords[1];}
100
- if(mouseY<this.gutterTop||mouseY>(ca.height-this.gutterBottom)||mouseX<this.gutterLeft||mouseX>(ca.width-this.gutterRight)){return null;}
101
- if(prop['chart.yaxispos']=='center'){var value=((mouseX-this.gutterLeft)/(this.graphwidth/2))*(this.max-prop['chart.xmin']);value=value-this.max
102
- if(prop['chart.xmin']>0){value=((mouseX-this.gutterLeft-(this.graphwidth/2))/(this.graphwidth/2))*(this.max-prop['chart.xmin']);value+=prop['chart.xmin'];if(mouseX<(this.gutterLeft+(this.graphwidth/2))){value-=(2*prop['chart.xmin']);}}}else if(prop['chart.yaxispos']=='right'){var value=((mouseX-this.gutterLeft)/this.graphwidth)*(this.scale2.max-prop['chart.xmin']);value=this.scale2.max-value;}else{var value=((mouseX-this.gutterLeft)/this.graphwidth)*(this.scale2.max-prop['chart.xmin']);value+=prop['chart.xmin'];}
103
- return value;};this.highlight=this.Highlight=function(shape)
104
- {if(typeof prop['chart.highlight.style']==='function'){(prop['chart.highlight.style'])(shape);}else{RG.Highlight.Rect(this,shape);}};this.getObjectByXY=function(e)
105
- {var mouseXY=RG.getMouseXY(e);if(prop['chart.variant']==='3d'){var adjustment=prop['chart.variant.threed.angle']*mouseXY[0];mouseXY[1]-=adjustment;}
106
- if(mouseXY[0]>=this.gutterLeft&&mouseXY[0]<=(ca.width-this.gutterRight)&&mouseXY[1]>=this.gutterTop&&mouseXY[1]<=(ca.height-this.gutterBottom)){return this;}};this.getXCoord=function(value)
107
- {if(prop['chart.yaxispos']=='center'){if(value>this.max||value<(-1*this.max)){return null;}
108
- var width=(ca.width-prop['chart.gutter.left']-prop['chart.gutter.right'])/2;var coord=(((value-prop['chart.xmin'])/(this.max-prop['chart.xmin']))*width)+width;coord=prop['chart.gutter.left']+coord;}else{if(value>this.max||value<0){return null;}
109
- var width=ca.width-prop['chart.gutter.left']-prop['chart.gutter.right'];var coord=((value-prop['chart.xmin'])/(this.max-prop['chart.xmin']))*width;coord=prop['chart.gutter.left']+coord;}
110
- return coord;};this.parseColors=function()
111
- {if(this.original_colors.length===0){this.original_colors['chart.colors']=RG.array_clone(prop['chart.colors']);this.original_colors['chart.background.grid.color']=RG.array_clone(prop['chart.background.grid.color']);this.original_colors['chart.background.color']=RG.array_clone(prop['chart.background.color']);this.original_colors['chart.background.barcolor1']=RG.array_clone(prop['chart.background.barcolor1']);this.original_colors['chart.background.barcolor2']=RG.array_clone(prop['chart.background.barcolor2']);this.original_colors['chart.text.color']=RG.array_clone(prop['chart.text.color']);this.original_colors['chart.labels.colors']=RG.array_clone(prop['chart.labels.colors']);this.original_colors['chart.strokestyle']=RG.array_clone(prop['chart.strokestyle']);this.original_colors['chart.axis.color']=RG.array_clone(prop['chart.axis.color']);this.original_colors['chart.highlight.fill']=RG.array_clone(prop['chart.highlight.fill']);this.original_colors['chart.highlight.stroke']=RG.array_clone(prop['chart.highlight.stroke']);}
112
- var colors=prop['chart.colors'];for(var i=0;i<colors.length;++i){colors[i]=this.parseSingleColorForGradient(colors[i]);}
113
- prop['chart.background.grid.color']=this.parseSingleColorForGradient(prop['chart.background.grid.color']);prop['chart.background.color']=this.parseSingleColorForGradient(prop['chart.background.color']);prop['chart.background.barcolor1']=this.parseSingleColorForGradient(prop['chart.background.barcolor1']);prop['chart.background.barcolor2']=this.parseSingleColorForGradient(prop['chart.background.barcolor2']);prop['chart.text.color']=this.parseSingleColorForGradient(prop['chart.text.color']);prop['chart.labels.colors']=this.parseSingleColorForGradient(prop['chart.labels.colors']);prop['chart.strokestyle']=this.parseSingleColorForGradient(prop['chart.strokestyle']);prop['chart.axis.color']=this.parseSingleColorForGradient(prop['chart.axis.color']);prop['chart.highlight.fill']=this.parseSingleColorForGradient(prop['chart.highlight.fill']);prop['chart.highlight.stroke']=this.parseSingleColorForGradient(prop['chart.highlight.stroke']);};this.reset=function()
114
- {};this.parseSingleColorForGradient=function(color)
115
- {if(!color||typeof(color)!='string'){return color;}
116
- if(color.match(/^gradient\((.*)\)$/i)){var parts=RegExp.$1.split(':');if(prop['chart.yaxispos']==='right'){parts=RG.arrayReverse(parts);}
117
- var grad=co.createLinearGradient(prop['chart.gutter.left'],0,ca.width-prop['chart.gutter.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]));}}
118
- return grad?grad:color;};this.interactiveKeyHighlight=function(index)
119
- {var obj=this;this.coords2.forEach(function(value,idx,arr)
120
- {var shape=obj.coords2[idx][index]
121
- var pre_linewidth=co.lineWidth;co.lineWidth=2;co.fillStyle=prop['chart.key.interactive.highlight.chart.fill'];co.strokeStyle=prop['chart.key.interactive.highlight.chart.stroke'];co.fillRect(shape[0],shape[1],shape[2],shape[3]);co.strokeRect(shape[0],shape[1],shape[2],shape[3]);co.lineWidth=pre_linewidth;});};this.on=function(type,func)
122
- {if(type.substr(0,2)!=='on'){type='on'+type;}
123
- if(typeof this[type]!=='function'){this[type]=func;}else{RG.addCustomEventListener(this,type,func);}
124
- return this;};this.firstDrawFunc=function()
125
- {};this.getShapeByY=function(e)
126
- {var mouseXY=RG.getMouseXY(e);var obj=arguments[1]?arguments[1]:this;for(var i=0,len=obj.coords.length;i<len;i++){if(obj.coords[i].length==0){continue;}
127
- var mouseX=mouseXY[0],mouseY=mouseXY[1],left=obj.coords[i][0],top=obj.coords[i][1],width=obj.coords[i][2],height=obj.coords[i][3];if(mouseY>=top&&mouseY<=(top+height)){if(prop['chart.tooltips']){var tooltip=RG.parseTooltipText?RG.parseTooltipText(prop['chart.tooltips'],i):prop['chart.tooltips'][i];}
128
- return{0:obj,object:obj,1:left,x:left,2:top,y:top,3:width,width:width,4:height,height:height,5:i,index:i,tooltip:tooltip};}}
129
- return null;};this.adjusting_mousemove=this.Adjusting_mousemove=function(e)
130
- {if(prop['chart.adjustable']&&RG.Registry.get('chart.adjusting')&&RG.Registry.get('chart.adjusting').uid==this.uid){var value=Number(this.getValue(e)),shape=RG.Registry.get('chart.adjusting.shape');if(shape){RG.Registry.Set('chart.adjusting.shape',shape);if(this.stackedOrGrouped&&prop['chart.grouping']=='grouped'){var indexes=RG.sequentialIndexToGrouped(shape['index'],this.data);if(typeof this.data[indexes[0]]=='number'){this.data[indexes[0]]=Number(value);}else if(!RG.is_null(this.data[indexes[0]])){this.data[indexes[0]][indexes[1]]=Number(value);}}else if(typeof this.data[shape['index']]=='number'){this.data[shape['index']]=Number(value);}
131
- RG.redrawCanvas(e.target);RG.fireCustomEvent(this,'onadjust');}}};this.grow=function()
132
- {var obj=this,opt=arguments[0]||{},frames=opt.frames||30,frame=0,callback=arguments[1]||function(){},labelsAbove=prop['chart.labels.above'];this.set('labelsAbove',false);obj.original_data=RG.arrayClone(obj.data);if(prop['chart.xmax']==0){var xmax=0;for(var i=0;i<obj.data.length;++i){if(RG.isArray(obj.data[i])&&prop['chart.grouping']=='stacked'){xmax=ma.max(xmax,RG.arraySum(obj.data[i]));}else if(RG.isArray(obj.data[i])&&prop['chart.grouping']=='grouped'){xmax=ma.max(xmax,RG.arrayMax(obj.data[i]));}else{xmax=ma.max(xmax,ma.abs(RG.arrayMax(obj.data[i])));}}
133
- var scale2=RG.getScale2(obj,{'max':xmax});obj.Set('chart.xmax',scale2.max);}
134
- function iterator()
135
- {for(var j=0,len=obj.original_data.length;j<len;++j){var easingFactor=RG.Effects.getEasingMultiplier(frames,frame);if(typeof obj.data[j]==='object'&&obj.data[j]){for(var k=0,len2=obj.data[j].length;k<len2;++k){obj.data[j][k]=RG.isNull(obj.data[j][k])?null:obj.original_data[j][k]*easingFactor;}}else{obj.data[j]=RG.isNull(obj.data[j])?null:obj.original_data[j]*easingFactor;}}
136
- RG.redrawCanvas(obj.canvas);if(frame<frames){frame+=1;RG.Effects.updateCanvas(iterator);}else{if(labelsAbove){obj.set('labelsAbove',true);RG.redraw();}
137
- callback(obj);}}
138
- iterator();return this;};this.wave=function()
139
- {var obj=this,opt=arguments[0]||{};opt.frames=opt.frames||60;opt.startFrames=[];opt.counters=[];var framesperbar=opt.frames/3,frame=-1,callback=arguments[1]||function(){},original=RG.arrayClone(obj.data),labelsAbove=prop['chart.labels.above'];this.set('labelsAbove',false);for(var i=0,len=obj.data.length;i<len;i+=1){opt.startFrames[i]=((opt.frames/2)/(obj.data.length-1))*i;if(typeof obj.data[i]==='object'&&obj.data[i]){opt.counters[i]=[];for(var j=0;j<obj.data[i].length;j++){opt.counters[i][j]=0;}}else{opt.counters[i]=0;}}
140
- obj.draw();obj.Set('xmax',obj.scale2.max);RG.clear(obj.canvas);function iterator()
141
- {++frame;for(var i=0,len=obj.data.length;i<len;i+=1){if(frame>opt.startFrames[i]){if(typeof obj.data[i]==='number'){obj.data[i]=ma.min(ma.abs(original[i]),ma.abs(original[i]*((opt.counters[i]++)/framesperbar)));if(original[i]<0){obj.data[i]*=-1;}}else if(!RG.isNull(obj.data[i])){for(var j=0,len2=obj.data[i].length;j<len2;j+=1){obj.data[i][j]=ma.min(ma.abs(original[i][j]),ma.abs(original[i][j]*((opt.counters[i][j]++)/framesperbar)));if(original[i][j]<0){obj.data[i][j]*=-1;}}}}else{obj.data[i]=typeof obj.data[i]==='object'&&obj.data[i]?RG.arrayPad([],obj.data[i].length,0):(RG.isNull(obj.data[i])?null:0);}}
142
- if(frame>=opt.frames){if(labelsAbove){obj.set('labelsAbove',true);RG.redrawCanvas(obj.canvas);}
143
- callback(obj);}else{RG.redrawCanvas(obj.canvas);RG.Effects.updateCanvas(iterator);}}
144
- iterator();return this;};this.isAdjustable=function(shape)
145
- {if(RG.isNull(prop['chart.adjustable.only'])){return true;}
146
- if(RG.isArray(prop['chart.adjustable.only'])&&prop['chart.adjustable.only'][shape.index]){return true;}
147
- return false;};RG.Register(this);if(parseConfObjectForOptions){RG.parseObjectStyleConfig(this,conf.options);}};
13
+ RGraph = window.RGraph || {isRGraph: true};
14
+
15
+ /**
16
+ * The horizontal bar chart constructor. The horizontal bar is a minor variant
17
+ * on the bar chart. If you have big labels, this may be useful as there is usually
18
+ * more space available for them.
19
+ *
20
+ * @param object canvas The canvas object
21
+ * @param array data The chart data
22
+ */
23
+ RGraph.HBar = function (conf)
24
+ {
25
+ /**
26
+ * Allow for object config style
27
+ */
28
+ if ( typeof conf === 'object'
29
+ && typeof conf.data === 'object'
30
+ && typeof conf.id === 'string') {
31
+
32
+ var id = conf.id
33
+ var canvas = document.getElementById(id);
34
+ var data = conf.data;
35
+ var parseConfObjectForOptions = true; // Set this so the config is parsed (at the end of the constructor)
36
+
37
+ } else {
38
+
39
+ var id = conf;
40
+ var canvas = document.getElementById(id);
41
+ var data = arguments[1];
42
+ }
43
+
44
+
45
+ this.id = id;
46
+ this.canvas = canvas;
47
+ this.context = this.canvas.getContext ? this.canvas.getContext("2d", {alpha: (typeof id === 'object' && id.alpha === false) ? false : true}) : null;
48
+ this.canvas.__object__ = this;
49
+ this.data = data;
50
+ this.type = 'hbar';
51
+ this.isRGraph = true;
52
+ this.uid = RGraph.CreateUID();
53
+ this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID();
54
+ this.colorsParsed = false;
55
+ this.coords = [];
56
+ this.coords2 = [];
57
+ this.coordsText = [];
58
+ this.original_colors = [];
59
+ this.firstDraw = true; // After the first draw this will be false
60
+
61
+
62
+
63
+
64
+ this.max = 0;
65
+ this.stackedOrGrouped = false;
66
+
67
+ // Default properties
68
+ this.properties =
69
+ {
70
+ 'chart.gutter.left': 75,
71
+ 'chart.gutter.left.autosize': false,
72
+ 'chart.gutter.right': 25,
73
+ 'chart.gutter.top': 25,
74
+ 'chart.gutter.bottom': 25,
75
+ 'chart.background.grid': true,
76
+ 'chart.background.grid.color': '#ddd',
77
+ 'chart.background.grid.width': 1,
78
+ 'chart.background.grid.hsize': 25,
79
+ 'chart.background.grid.vsize': 25,
80
+ 'chart.background.barcolor1': 'rgba(0,0,0,0)',
81
+ 'chart.background.barcolor2': 'rgba(0,0,0,0)',
82
+ 'chart.background.grid.hlines': true,
83
+ 'chart.background.grid.vlines': true,
84
+ 'chart.background.grid.border': true,
85
+ 'chart.background.grid.autofit':true,
86
+ 'chart.background.grid.autofit.align':true,
87
+ 'chart.background.grid.autofit.numhlines': null,
88
+ 'chart.background.grid.autofit.numvlines': 5,
89
+ 'chart.background.grid.dashed': false,
90
+ 'chart.background.grid.dotted': false,
91
+ 'chart.background.color': null,
92
+ 'chart.linewidth': 1,
93
+ 'chart.title': '',
94
+ 'chart.title.background': null,
95
+ 'chart.title.xaxis': '',
96
+ 'chart.title.xaxis.bold': true,
97
+ 'chart.title.xaxis.size': null,
98
+ 'chart.title.xaxis.font': null,
99
+ 'chart.title.yaxis': '',
100
+ 'chart.title.yaxis.bold': true,
101
+ 'chart.title.yaxis.size': null,
102
+ 'chart.title.yaxis.font': null,
103
+ 'chart.title.yaxis.color': null,
104
+ 'chart.title.xaxis.pos': null,
105
+ 'chart.title.yaxis.pos': 0.8,
106
+ 'chart.title.yaxis.x': null,
107
+ 'chart.title.yaxis.y': null,
108
+ 'chart.title.xaxis.x': null,
109
+ 'chart.title.xaxis.y': null,
110
+ 'chart.title.xaxis.color': null,
111
+ 'chart.title.hpos': null,
112
+ 'chart.title.vpos': null,
113
+ 'chart.title.bold': true,
114
+ 'chart.title.font': null,
115
+ 'chart.title.x': null,
116
+ 'chart.title.y': null,
117
+ 'chart.title.halign': null,
118
+ 'chart.title.valign': null,
119
+ 'chart.text.size': 12,
120
+ 'chart.text.color': 'black',
121
+ 'chart.text.font': 'Segoe UI, Arial, Verdana, sans-serif',
122
+ 'chart.text.accessible': true,
123
+ 'chart.text.accessible.overflow': 'visible',
124
+ 'chart.text.accessible.pointerevents': true,
125
+ 'chart.colors': ['red', 'blue', 'green', 'pink', 'yellow', 'cyan', 'navy', 'gray', 'black'],
126
+ 'chart.colors.sequential': false,
127
+ 'chart.xlabels.specific': null,
128
+ 'chart.labels': [],
129
+ 'chart.labels.bold': false,
130
+ 'chart.labels.color': null,
131
+
132
+ 'chart.labels.above': false,
133
+ 'chart.labels.above.decimals': 0,
134
+ 'chart.labels.above.specific': null,
135
+ 'chart.labels.above.color': null,
136
+ 'chart.labels.above.units.pre': '',
137
+ 'chart.labels.above.units.post': '',
138
+ 'chart.labels.above.font': null,
139
+ 'chart.labels.above.size': null,
140
+ 'chart.labels.above.bold': false,
141
+ 'chart.labels.above.italic': false,
142
+
143
+ 'chart.labels.offsetx': 0,
144
+ 'chart.labels.offsety': 0,
145
+ 'chart.xlabels.offsetx': 0,
146
+ 'chart.xlabels.offsety': 0,
147
+ 'chart.xlabels': true,
148
+ 'chart.xlabels.count': 5,
149
+ 'chart.contextmenu': null,
150
+ 'chart.key': null,
151
+ 'chart.key.background': 'white',
152
+ 'chart.key.position': 'graph',
153
+ 'chart.key.halign': 'right',
154
+ 'chart.key.shadow': false,
155
+ 'chart.key.shadow.color': '#666',
156
+ 'chart.key.shadow.blur': 3,
157
+ 'chart.key.shadow.offsetx': 2,
158
+ 'chart.key.shadow.offsety': 2,
159
+ 'chart.key.position.gutter.boxed': false,
160
+ 'chart.key.position.x': null,
161
+ 'chart.key.position.y': null,
162
+ 'chart.key.color.shape': 'square',
163
+ 'chart.key.rounded': true,
164
+ 'chart.key.linewidth': 1,
165
+ 'chart.key.colors': null,
166
+ 'chart.key.interactive': false,
167
+ 'chart.key.interactive.highlight.chart.stroke': 'black',
168
+ 'chart.key.interactive.highlight.chart.fill':'rgba(255,255,255,0.7)',
169
+ 'chart.key.interactive.highlight.label':'rgba(255,0,0,0.2)',
170
+ 'chart.key.text.color': 'black',
171
+ 'chart.units.pre': '',
172
+ 'chart.units.post': '',
173
+ 'chart.units.ingraph': false,
174
+ 'chart.strokestyle': 'rgba(0,0,0,0)',
175
+ 'chart.xmin': 0,
176
+ 'chart.xmax': 0,
177
+ 'chart.axis.color': 'black',
178
+ 'chart.shadow': false,
179
+ 'chart.shadow.color': '#666',
180
+ 'chart.shadow.blur': 3,
181
+ 'chart.shadow.offsetx': 3,
182
+ 'chart.shadow.offsety': 3,
183
+ 'chart.vmargin': 2,
184
+ 'chart.vmargin.grouped': 2,
185
+ 'chart.grouping': 'grouped',
186
+ 'chart.tooltips': null,
187
+ 'chart.tooltips.event': 'onclick',
188
+ 'chart.tooltips.effect': 'fade',
189
+ 'chart.tooltips.css.class': 'RGraph_tooltip',
190
+ 'chart.tooltips.highlight': true,
191
+ 'chart.highlight.fill': 'rgba(255,255,255,0.7)',
192
+ 'chart.highlight.stroke': 'rgba(0,0,0,0)',
193
+ 'chart.highlight.style': null,
194
+ 'chart.annotatable': false,
195
+ 'chart.annotate.color': 'black',
196
+ 'chart.zoom.factor': 1.5,
197
+ 'chart.zoom.fade.in': true,
198
+ 'chart.zoom.fade.out': true,
199
+ 'chart.zoom.hdir': 'right',
200
+ 'chart.zoom.vdir': 'down',
201
+ 'chart.zoom.frames': 25,
202
+ 'chart.zoom.delay': 16.666,
203
+ 'chart.zoom.shadow': true,
204
+ 'chart.zoom.background': true,
205
+ 'chart.zoom.action': 'zoom',
206
+ 'chart.resizable': false,
207
+ 'chart.resize.handle.adjust': [0,0],
208
+ 'chart.resize.handle.background': null,
209
+ 'chart.scale.point': '.',
210
+ 'chart.scale.thousand': ',',
211
+ 'chart.scale.decimals': null,
212
+ 'chart.scale.zerostart': true,
213
+ 'chart.noredraw': false,
214
+ 'chart.events.click': null,
215
+ 'chart.events.mousemove': null,
216
+ 'chart.noxaxis': false,
217
+ 'chart.noyaxis': false,
218
+ 'chart.noaxes': false,
219
+ 'chart.noxtickmarks': false,
220
+ 'chart.noytickmarks': false,
221
+ 'chart.numyticks': data.length,
222
+ 'chart.numxticks': 10,
223
+ 'chart.variant': 'hbar',
224
+ 'chart.variant.threed.angle': 0.1,
225
+ 'chart.variant.threed.offsetx': 10,
226
+ 'chart.variant.threed.offsety': 5,
227
+ 'chart.variant.threed.xaxis': true,
228
+ 'chart.variant.threed.yaxis': true,
229
+ 'chart.yaxispos': 'left',
230
+ 'chart.variant': 'hbar',
231
+ 'chart.clearto': 'rgba(0,0,0,0)',
232
+ 'chart.adjustable': false,
233
+ 'chart.adjustable.only': null
234
+ }
235
+
236
+ // Check for support
237
+ if (!this.canvas) {
238
+ alert('[HBAR] No canvas support');
239
+ return;
240
+ }
241
+
242
+ // This loop is used to check for stacked or grouped charts and now
243
+ // also to convert strings to numbers. And now also undefined values
244
+ // (29/07/2016
245
+ for (i=0,len=this.data.length; i<len; ++i) {
246
+ if (typeof this.data[i] == 'object' && !RGraph.isNull(this.data[i])) {
247
+
248
+ this.stackedOrGrouped = true;
249
+
250
+ for (var j=0,len2=this.data[i].length; j<len2; ++j) {
251
+ if (typeof this.data[i][j] === 'string') {
252
+ this.data[i][j] = parseFloat(this.data[i][j]);
253
+ }
254
+ }
255
+
256
+ } else if (typeof this.data[i] == 'string') {
257
+ this.data[i] = parseFloat(this.data[i]) || 0;
258
+
259
+ } else if (typeof this.data[i] === 'undefined') {
260
+ this.data[i] = null;
261
+ }
262
+ }
263
+
264
+
265
+ /**
266
+ * Create the dollar objects so that functions can be added to them
267
+ */
268
+ var linear_data = RGraph.arrayLinearize(data);
269
+ for (var i=0,len=linear_data.length; i<len; ++i) {
270
+ this['$' + i] = {};
271
+ }
272
+
273
+
274
+
275
+ /**
276
+ * Create the linear data array
277
+ */
278
+ this.data_arr = RGraph.arrayLinearize(this.data);
279
+
280
+
281
+ /**
282
+ * Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
283
+ * done already
284
+ */
285
+ if (!this.canvas.__rgraph_aa_translated__) {
286
+ this.context.translate(0.5,0.5);
287
+
288
+ this.canvas.__rgraph_aa_translated__ = true;
289
+ }
290
+
291
+
292
+
293
+
294
+ // Short variable names
295
+ var RG = RGraph,
296
+ ca = this.canvas,
297
+ co = ca.getContext('2d'),
298
+ prop = this.properties,
299
+ pa2 = RG.path2,
300
+ win = window,
301
+ doc = document,
302
+ ma = Math
303
+
304
+
305
+
306
+ /**
307
+ * "Decorate" the object with the generic effects if the effects library has been included
308
+ */
309
+ if (RG.Effects && typeof RG.Effects.decorate === 'function') {
310
+ RG.Effects.decorate(this);
311
+ }
312
+
313
+
314
+
315
+
316
+ /**
317
+ * A setter
318
+ *
319
+ * @param name string The name of the property to set
320
+ * @param value mixed The value of the property
321
+ */
322
+ this.set =
323
+ this.Set = function (name)
324
+ {
325
+ var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
326
+
327
+ /**
328
+ * the number of arguments is only one and it's an
329
+ * object - parse it for configuration data and return.
330
+ */
331
+ if (arguments.length === 1 && typeof name === 'object') {
332
+ RG.parseObjectStyleConfig(this, name);
333
+ return this;
334
+ }
335
+
336
+
337
+
338
+
339
+ /**
340
+ * This should be done first - prepend the propertyy name with "chart." if necessary
341
+ */
342
+ if (name.substr(0,6) != 'chart.') {
343
+ name = 'chart.' + name;
344
+ }
345
+
346
+
347
+
348
+ // Convert uppercase letters to dot+lower case letter
349
+ while(name.match(/([A-Z])/)) {
350
+ name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
351
+ }
352
+
353
+ if (name == 'chart.labels.abovebar') {
354
+ name = 'chart.labels.above';
355
+ }
356
+
357
+ prop[name] = value;
358
+
359
+ return this;
360
+ };
361
+
362
+
363
+
364
+
365
+ /**
366
+ * A getter
367
+ *
368
+ * @param name string The name of the property to get
369
+ */
370
+ this.get =
371
+ this.Get = function (name)
372
+ {
373
+ /**
374
+ * This should be done first - prepend the property name with "chart." if necessary
375
+ */
376
+ if (name.substr(0,6) != 'chart.') {
377
+ name = 'chart.' + name;
378
+ }
379
+
380
+ // Convert uppercase letters to dot+lower case letter
381
+ while(name.match(/([A-Z])/)) {
382
+ name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
383
+ }
384
+
385
+
386
+ if (name == 'chart.labels.abovebar') {
387
+ name = 'chart.labels.above';
388
+ }
389
+
390
+ return prop[name];
391
+ };
392
+
393
+
394
+
395
+
396
+ /**
397
+ * The function you call to draw the bar chart
398
+ */
399
+ this.draw =
400
+ this.Draw = function ()
401
+ {
402
+ /**
403
+ * Fire the onbeforedraw event
404
+ */
405
+ RG.fireCustomEvent(this, 'onbeforedraw');
406
+
407
+
408
+ //
409
+ // Check that the bHBar isn't stacked with adjusting enabled
410
+ //
411
+ if (prop['chart.adjustable'] && prop['chart.grouping'] === 'stacked') {
412
+ alert('[RGRAPH] The HBar does not support stacked charts with adjusting');
413
+ }
414
+
415
+ //
416
+ // If the chart is 3d then angle it it
417
+ //
418
+
419
+ if (prop['chart.variant'] === '3d') {
420
+
421
+ if (prop['chart.text.accessible']) {
422
+ // Nada
423
+ } else {
424
+ co.setTransform(1,prop['chart.variant.threed.angle'],0,1,0.5,0.5);
425
+ }
426
+
427
+ // Enlarge the gutter if its 25
428
+ if (prop['chart.gutter.bottom'] === 25) {
429
+ this.set('gutterBottom', 80);
430
+ }
431
+ }
432
+
433
+
434
+
435
+
436
+ /**
437
+ * Parse the colors. This allows for simple gradient syntax
438
+ */
439
+ if (!this.colorsParsed) {
440
+ this.parseColors();
441
+
442
+ // Don't want to do this again
443
+ this.colorsParsed = true;
444
+ }
445
+
446
+
447
+
448
+
449
+
450
+
451
+ /**
452
+ * Accomodate autosizing the left gutter
453
+ */
454
+ if (prop['chart.gutter.left.autosize']) {
455
+ var len = 0;
456
+ var labels = prop['chart.labels'];
457
+ var font = prop['chart.text.font'];
458
+ var size = prop['chart.text.size'];
459
+
460
+ for (var i=0; i<labels.length; i+=1) {
461
+ var length = RG.measureText(labels[i], false, font, size)[0] || 0
462
+ len = ma.max(len, length);
463
+ }
464
+
465
+ prop['chart.gutter.left'] = len + 10;
466
+ }
467
+
468
+
469
+
470
+
471
+
472
+
473
+
474
+
475
+
476
+
477
+
478
+
479
+
480
+ /**
481
+ * This is new in May 2011 and facilitates indiviual gutter settings,
482
+ * eg chart.gutter.left
483
+ */
484
+ this.gutterLeft = prop['chart.gutter.left'];
485
+ this.gutterRight = prop['chart.gutter.right'];
486
+ this.gutterTop = prop['chart.gutter.top'];
487
+ this.gutterBottom = prop['chart.gutter.bottom'];
488
+
489
+
490
+
491
+
492
+ /**
493
+ * Stop the coords array from growing uncontrollably
494
+ */
495
+ this.coords = [];
496
+ this.coords2 = [];
497
+ this.coordsText = [];
498
+ this.max = 0;
499
+
500
+ /**
501
+ * Check for chart.xmin in stacked charts
502
+ */
503
+ if (prop['chart.xmin'] > 0 && prop['chart.grouping'] == 'stacked') {
504
+ alert('[HBAR] Using chart.xmin is not supported with stacked charts, resetting chart.xmin to zero');
505
+ this.Set('chart.xmin', 0);
506
+ }
507
+
508
+ /**
509
+ * Work out a few things. They need to be here because they depend on things you can change before you
510
+ * call Draw() but after you instantiate the object
511
+ */
512
+ this.graphwidth = ca.width - this.gutterLeft - this.gutterRight;
513
+ this.graphheight = ca.height - this.gutterTop - this.gutterBottom;
514
+ this.halfgrapharea = this.grapharea / 2;
515
+ this.halfTextHeight = prop['chart.text.size'] / 2;
516
+ this.halfway = ma.round((this.graphwidth / 2) + this.gutterLeft)
517
+
518
+
519
+
520
+
521
+
522
+
523
+
524
+
525
+
526
+
527
+ // Progressively Draw the chart
528
+ RG.Background.draw(this);
529
+
530
+ this.drawbars();
531
+ this.drawAxes();
532
+ this.drawLabels();
533
+
534
+
535
+ // Draw the key if necessary
536
+ if (prop['chart.key'] && prop['chart.key'].length) {
537
+ RG.DrawKey(this, prop['chart.key'], prop['chart.colors']);
538
+ }
539
+
540
+
541
+
542
+ /**
543
+ * Setup the context menu if required
544
+ */
545
+ if (prop['chart.contextmenu']) {
546
+ RG.ShowContext(this);
547
+ }
548
+
549
+
550
+
551
+ /**
552
+ * Draw "in graph" labels
553
+ */
554
+ RG.DrawInGraphLabels(this);
555
+
556
+
557
+ /**
558
+ * This function enables resizing
559
+ */
560
+ if (prop['chart.resizable']) {
561
+ RG.AllowResizing(this);
562
+ }
563
+
564
+
565
+ /**
566
+ * This installs the event listeners
567
+ */
568
+ RG.InstallEventListeners(this);
569
+
570
+
571
+ /**
572
+ * Fire the onfirstdraw event
573
+ */
574
+ if (this.firstDraw) {
575
+ RG.fireCustomEvent(this, 'onfirstdraw');
576
+ this.firstDraw = false;
577
+ this.firstDrawFunc();
578
+ }
579
+
580
+
581
+
582
+ /**
583
+ * Fire the RGraph ondraw event
584
+ */
585
+ RG.FireCustomEvent(this, 'ondraw');
586
+
587
+ return this;
588
+ };
589
+
590
+
591
+
592
+ /**
593
+ * Used in chaining. Runs a function there and then - not waiting for
594
+ * the events to fire (eg the onbeforedraw event)
595
+ *
596
+ * @param function func The function to execute
597
+ */
598
+ this.exec = function (func)
599
+ {
600
+ func(this);
601
+
602
+ return this;
603
+ };
604
+
605
+
606
+
607
+
608
+ /**
609
+ * This draws the axes
610
+ */
611
+ this.drawAxes =
612
+ this.DrawAxes = function ()
613
+ {
614
+ var halfway = this.halfway
615
+
616
+
617
+
618
+
619
+
620
+
621
+ co.beginPath();
622
+
623
+ co.lineWidth = prop['chart.axis.linewidth'] ? prop['chart.axis.linewidth'] + 0.001 : 1.001;
624
+ co.strokeStyle = prop['chart.axis.color'];
625
+
626
+
627
+
628
+
629
+ // Draw the Y axis
630
+ if (prop['chart.noyaxis'] == false && prop['chart.noaxes'] == false) {
631
+ if (prop['chart.yaxispos'] == 'center') {
632
+ co.moveTo(halfway, this.gutterTop);
633
+ co.lineTo(halfway, ca.height - this.gutterBottom);
634
+
635
+ } else if (prop['chart.yaxispos'] == 'right') {
636
+ co.moveTo(ca.width - this.gutterRight, this.gutterTop);
637
+ co.lineTo(ca.width - this.gutterRight, ca.height - this.gutterBottom);
638
+
639
+ } else {
640
+ co.moveTo(this.gutterLeft, this.gutterTop);
641
+ co.lineTo(this.gutterLeft, ca.height - this.gutterBottom);
642
+ }
643
+ }
644
+
645
+ // Draw the X axis
646
+ if (prop['chart.noxaxis'] == false && prop['chart.noaxes'] == false) {
647
+ co.moveTo(this.gutterLeft +0.001, ca.height - this.gutterBottom + 0.001);
648
+ co.lineTo(ca.width - this.gutterRight + 0.001, ca.height - this.gutterBottom + 0.001);
649
+ }
650
+
651
+ // Draw the Y tickmarks
652
+ if ( prop['chart.noytickmarks'] == false
653
+ && prop['chart.noyaxis'] == false
654
+ && prop['chart.numyticks'] > 0
655
+ && prop['chart.noaxes'] == false
656
+ ) {
657
+
658
+ var yTickGap = (ca.height - this.gutterTop - this.gutterBottom) / (prop['chart.numyticks'] > 0 ? prop['chart.numyticks'] : this.data.length);
659
+
660
+ for (y=this.gutterTop; y<(ca.height - this.gutterBottom - 1); y+=yTickGap) {
661
+ if (prop['chart.yaxispos'] == 'center') {
662
+ co.moveTo(halfway + 3, ma.round(y));
663
+ co.lineTo(halfway - 3, ma.round(y));
664
+
665
+ } else if (prop['chart.yaxispos'] == 'right') {
666
+ co.moveTo(ca.width - this.gutterRight, ma.round(y));
667
+ co.lineTo(ca.width - this.gutterRight + 3, ma.round(y));
668
+
669
+ } else {
670
+ co.moveTo(this.gutterLeft, ma.round(y));
671
+ co.lineTo( this.gutterLeft - 3, ma.round(y));
672
+ }
673
+ }
674
+
675
+ // If the X axis isn't being shown draw the end tick
676
+ if (prop['chart.noxaxis'] == true) {
677
+ if (prop['chart.yaxispos'] == 'center') {
678
+ co.moveTo(halfway + 3, ma.round(y));
679
+ co.lineTo(halfway - 3, ma.round(y));
680
+
681
+ } else if (prop['chart.yaxispos'] == 'right') {
682
+ co.moveTo(ca.width - this.gutterRight, ma.round(y));
683
+ co.lineTo(ca.width - this.gutterRight + 3, ma.round(y));
684
+
685
+ } else {
686
+ co.moveTo(this.gutterLeft, ma.round(y));
687
+ co.lineTo( this.gutterLeft - 3, ma.round(y));
688
+ }
689
+ }
690
+ }
691
+
692
+
693
+ // Draw the X tickmarks
694
+ if ( prop['chart.noxtickmarks'] == false
695
+ && prop['chart.noxaxis'] == false
696
+ && prop['chart.numxticks'] > 0
697
+ && prop['chart.noaxes'] == false) {
698
+
699
+ xTickGap = (ca.width - this.gutterLeft - this.gutterRight ) / prop['chart.numxticks'];
700
+ yStart = ca.height - this.gutterBottom;
701
+ yEnd = (ca.height - this.gutterBottom) + 3;
702
+
703
+
704
+
705
+
706
+
707
+ var i = prop['chart.numxticks']
708
+
709
+ while(i--) {
710
+
711
+ var x = ca.width - this.gutterRight - (i * xTickGap);
712
+
713
+ if (prop['chart.yaxispos'] === 'right') {
714
+ x -= xTickGap;
715
+ }
716
+
717
+ co.moveTo(ma.round(x), yStart);
718
+ co.lineTo(ma.round(x), yEnd);
719
+ }
720
+
721
+
722
+
723
+ if (prop['chart.yaxispos'] === 'center') {
724
+ var i = 5; while (i--) {
725
+ var x = this.gutterLeft + (xTickGap * i);
726
+
727
+ co.moveTo(ma.round(x), yStart);
728
+ co.lineTo(ma.round(x), yEnd);
729
+
730
+ }
731
+ }
732
+
733
+
734
+
735
+
736
+
737
+ // If the Y axis isn't being shown draw the end tick
738
+ if (prop['chart.noyaxis'] == true) {
739
+ co.moveTo(this.gutterLeft, ma.round(yStart));
740
+ co.lineTo( this.gutterLeft, ma.round(yEnd));
741
+ }
742
+ }
743
+ co.stroke();
744
+
745
+ /**
746
+ * Reset the linewidth
747
+ */
748
+ co.lineWidth = 1;
749
+ };
750
+
751
+
752
+
753
+
754
+ /**
755
+ * This draws the labels for the graph
756
+ */
757
+ this.drawLabels =
758
+ this.DrawLabels = function ()
759
+ {
760
+ var units_pre = prop['chart.units.pre'],
761
+ units_post = prop['chart.units.post'],
762
+ text_size = prop['chart.text.size'],
763
+ font = prop['chart.text.font'],
764
+ offsetx = prop['chart.xlabels.offsetx'],
765
+ offsety = prop['chart.xlabels.offsety']
766
+
767
+
768
+
769
+ /**
770
+ * Set the units to blank if they're to be used for ingraph labels only
771
+ */
772
+ if (prop['chart.units.ingraph']) {
773
+ units_pre = '';
774
+ units_post = '';
775
+ }
776
+
777
+
778
+ /**
779
+ * Draw the X axis labels
780
+ */
781
+ if (prop['chart.xlabels']) {
782
+
783
+ /**
784
+ * Specific X labels
785
+ */
786
+ if (RG.isArray(prop['chart.xlabels.specific'])) {
787
+
788
+ if (prop['chart.yaxispos'] == 'center') {
789
+
790
+ var halfGraphWidth = this.graphwidth / 2;
791
+ var labels = prop['chart.xlabels.specific'];
792
+ var interval = (this.graphwidth / 2) / (labels.length - 1);
793
+
794
+ co.fillStyle = prop['chart.text.color'];
795
+
796
+ for (var i=0; i<labels.length; i+=1) {
797
+ RG.text2(this, {
798
+ 'font':font,
799
+ 'size':text_size,
800
+ 'x':this.gutterLeft + halfGraphWidth + (interval * i) + offsetx,
801
+ 'y':ca.height - this.gutterBottom + offsetx,
802
+ 'text':labels[i],
803
+ 'valign':'top',
804
+ 'halign':'center',
805
+ 'tag': 'scale'
806
+ });
807
+ }
808
+
809
+ for (var i=(labels.length - 1); i>0; i-=1) {
810
+ RG.Text2(this, {
811
+ 'font':font,
812
+ 'size':text_size,
813
+ 'x':this.gutterLeft + (interval * (labels.length - i - 1)) + offsetx,
814
+ 'y':ca.height - this.gutterBottom + offsety,
815
+ 'text':labels[i],
816
+ 'valign':'top',
817
+ 'halign':'center',
818
+ 'tag': 'scale'
819
+ });
820
+ }
821
+
822
+ } else if (prop['chart.yaxispos'] == 'right') {
823
+
824
+ var labels = prop['chart.xlabels.specific'];
825
+ var interval = this.graphwidth / (labels.length - 1);
826
+
827
+ co.fillStyle = prop['chart.text.color'];
828
+
829
+ for (var i=0; i<labels.length; i+=1) {
830
+ RG.text2(this, {
831
+ 'font': font,
832
+ 'size': text_size,
833
+ 'x': this.gutterLeft + (interval * i) + offsetx,
834
+ 'y': ca.height - this.gutterBottom + offsety,
835
+ 'text': labels[labels.length - i - 1],
836
+ 'valign':'top',
837
+ 'halign':'center',
838
+ 'tag': 'scale'
839
+ });
840
+ }
841
+
842
+ } else {
843
+
844
+ var labels = prop['chart.xlabels.specific'];
845
+ var interval = this.graphwidth / (labels.length - 1);
846
+
847
+ co.fillStyle = prop['chart.text.color'];
848
+
849
+ for (var i=0; i<labels.length; i+=1) {
850
+ RG.text2(this, {
851
+ font: font,
852
+ size: text_size,
853
+ x: this.gutterLeft + (interval * i) + offsetx,
854
+ y: ca.height - this.gutterBottom + offsety,
855
+ text: labels[i],
856
+ valign:'top',
857
+ halign:'center',
858
+ tag: 'scale'
859
+ });
860
+ }
861
+ }
862
+
863
+ /**
864
+ * Draw an X scale
865
+ */
866
+ } else {
867
+
868
+ var gap = 7;
869
+
870
+ co.beginPath();
871
+ co.fillStyle = prop['chart.text.color'];
872
+
873
+
874
+ if (prop['chart.yaxispos'] == 'center') {
875
+
876
+ for (var i=0; i<this.scale2.labels.length; ++i) {
877
+ RG.text2(this, {
878
+ 'font':font,
879
+ 'size':text_size,
880
+ 'x':this.gutterLeft + (this.graphwidth / 2) - ((this.graphwidth / 2) * ((i+1)/this.scale2.labels.length)) + offsetx,
881
+ 'y':this.gutterTop + this.halfTextHeight + this.graphheight + gap + offsety,
882
+ 'text':'-' + this.scale2.labels[i],
883
+ 'valign':'center',
884
+ 'halign':'center',
885
+ 'tag': 'scale'
886
+ });
887
+ }
888
+
889
+ for (var i=0; i<this.scale2.labels.length; ++i) {
890
+ RG.text2(this, {
891
+ 'font':font,
892
+ 'size':text_size,
893
+ 'x':this.gutterLeft + ((this.graphwidth / 2) * ((i+1)/this.scale2.labels.length)) + (this.graphwidth / 2) + offsetx,
894
+ 'y':this.gutterTop + this.halfTextHeight + this.graphheight + gap + offsety,
895
+ 'text':this.scale2.labels[i],
896
+ 'valign':'center',
897
+ 'halign':'center',
898
+ 'tag': 'scale'
899
+ });
900
+ }
901
+
902
+ }else if (prop['chart.yaxispos'] == 'right') {
903
+
904
+
905
+ for (var i=0,len=this.scale2.labels.length; i<len; ++i) {
906
+ RG.Text2(this, {
907
+ 'font':font,
908
+ 'size':text_size,
909
+ 'x':this.gutterLeft + (i * (this.graphwidth / len)) + offsetx,
910
+ 'y':this.gutterTop + this.halfTextHeight + this.graphheight + gap + offsety,
911
+ 'text':'-' + this.scale2.labels[len - 1 - i],
912
+ 'valign':'center',
913
+ 'halign':'center',
914
+ 'tag': 'scale'
915
+ });
916
+ }
917
+
918
+
919
+ } else {
920
+ for (var i=0,len=this.scale2.labels.length; i<len; ++i) {
921
+ RG.Text2(this, {
922
+ 'font':font,
923
+ 'size':text_size,
924
+ 'x':this.gutterLeft + (this.graphwidth * ((i+1)/len)) + offsetx,
925
+ 'y':this.gutterTop + this.halfTextHeight + this.graphheight + gap + offsety,
926
+ 'text':this.scale2.labels[i],
927
+ 'valign':'center',
928
+ 'halign':'center',
929
+ 'tag': 'scale'
930
+ });
931
+ }
932
+ }
933
+
934
+ /**
935
+ * If xmin is not zero - draw that
936
+ */
937
+ if (prop['chart.xmin'] > 0 || prop['chart.noyaxis'] == true || prop['chart.scale.zerostart'] || prop['chart.noaxes']) {
938
+
939
+ var x = prop['chart.yaxispos'] == 'center' ? this.gutterLeft + (this.graphwidth / 2): this.gutterLeft;
940
+
941
+ /**
942
+ * Y axis on the right
943
+ */
944
+ if (prop['chart.yaxispos'] === 'right') {
945
+ var x = ca.width - this.gutterRight;
946
+ }
947
+
948
+ RG.text2(this, {
949
+ 'font':font,
950
+ 'size':text_size,
951
+ 'x':x + offsetx,
952
+ 'y':this.gutterTop + this.halfTextHeight + this.graphheight + gap + offsety,
953
+ 'text':RG.numberFormat(this, prop['chart.xmin'].toFixed(prop['chart.xmin'] === 0 ? 0 : prop['chart.scale.decimals']), units_pre, units_post),
954
+ 'valign':'center',
955
+ 'halign':'center',
956
+ 'tag': 'scale'
957
+ });
958
+ }
959
+
960
+ co.fill();
961
+ co.stroke();
962
+ }
963
+ }
964
+
965
+
966
+
967
+
968
+
969
+
970
+
971
+ /**
972
+ * The Y axis labels
973
+ */
974
+ if (typeof prop['chart.labels'] == 'object') {
975
+
976
+ var xOffset = prop['chart.variant'] === '3d' && prop['chart.yaxispos'] === 'right' ? 15 : 5,
977
+ font = prop['chart.text.font'],
978
+ color = prop['chart.labels.color'] || prop['chart.text.color'],
979
+ bold = prop['chart.labels.bold'],
980
+ offsetx = prop['chart.labels.offsetx'],
981
+ offsety = prop['chart.labels.offsety']
982
+
983
+
984
+ // Draw the X axis labels
985
+ co.fillStyle = color;
986
+
987
+ // How high is each bar
988
+ var barHeight = (ca.height - this.gutterTop - this.gutterBottom ) / prop['chart.labels'].length;
989
+
990
+ // Reset the yTickGap
991
+ yTickGap = (ca.height - this.gutterTop - this.gutterBottom) / prop['chart.labels'].length
992
+
993
+ /**
994
+ * If the Y axis is on the right set the alignment and the X position, otherwise on the left
995
+ */
996
+ if (prop['chart.yaxispos'] === 'right') {
997
+ var x = ca.width - this.gutterRight + xOffset;
998
+ var halign = 'left'
999
+ } else {
1000
+ var x = this.gutterLeft - xOffset;
1001
+ var halign = 'right'
1002
+ }
1003
+
1004
+ // Draw the X tickmarks
1005
+ var i=0;
1006
+ for (y=this.gutterTop + (yTickGap / 2); y<=ca.height - this.gutterBottom; y+=yTickGap) {
1007
+
1008
+ RG.text2(this, {
1009
+ 'font': font,
1010
+ 'size': prop['chart.text.size'],
1011
+ 'bold': bold,
1012
+ 'x': x + offsetx,
1013
+ 'y': y + offsety,
1014
+ 'text': String(prop['chart.labels'][i++]),
1015
+ 'halign': halign,
1016
+ 'valign': 'center',
1017
+ 'tag': 'labels'
1018
+ });
1019
+ }
1020
+ }
1021
+ };
1022
+
1023
+
1024
+
1025
+
1026
+ /**
1027
+ * This function draws the bars. It also draw 3D axes as the axes drawing bit
1028
+ * is don AFTER the bars are drawn
1029
+ */
1030
+ this.drawbars =
1031
+ this.Drawbars = function ()
1032
+ {
1033
+ co.lineWidth = prop['chart.linewidth'];
1034
+ co.strokeStyle = prop['chart.strokestyle'];
1035
+ co.fillStyle = prop['chart.colors'][0];
1036
+
1037
+ var prevX = 0,
1038
+ prevY = 0;
1039
+
1040
+
1041
+ /**
1042
+ * Work out the max value
1043
+ */
1044
+ if (prop['chart.xmax']) {
1045
+
1046
+ this.scale2 = RG.getScale2(this, {
1047
+ 'max':prop['chart.xmax'],
1048
+ 'min':prop['chart.xmin'],
1049
+ 'scale.decimals':Number(prop['chart.scale.decimals']),
1050
+ 'scale.point':prop['chart.scale.point'],
1051
+ 'scale.thousand':prop['chart.scale.thousand'],
1052
+ 'scale.round':prop['chart.scale.round'],
1053
+ 'units.pre':prop['chart.units.pre'],
1054
+ 'units.post':prop['chart.units.post'],
1055
+ 'ylabels.count':prop['chart.xlabels.count'],
1056
+ 'strict':true
1057
+ });
1058
+
1059
+ this.max = this.scale2.max;
1060
+
1061
+ } else {
1062
+
1063
+ var grouping = prop['chart.grouping'];
1064
+
1065
+ for (i=0; i<this.data.length; ++i) {
1066
+ if (typeof(this.data[i]) == 'object') {
1067
+ var value = grouping == 'grouped' ? Number(RG.array_max(this.data[i], true)) : Number(RG.array_sum(this.data[i])) ;
1068
+ } else {
1069
+ var value = Number(ma.abs(this.data[i]));
1070
+ }
1071
+
1072
+ this.max = ma.max(Math.abs(this.max), Math.abs(value));
1073
+ }
1074
+
1075
+ this.scale2 = RG.getScale2(this, {
1076
+ 'max':this.max,
1077
+ 'min':prop['chart.xmin'],
1078
+ 'scale.decimals':Number(prop['chart.scale.decimals']),
1079
+ 'scale.point':prop['chart.scale.point'],
1080
+ 'scale.thousand':prop['chart.scale.thousand'],
1081
+ 'scale.round':prop['chart.scale.round'],
1082
+ 'units.pre':prop['chart.units.pre'],
1083
+ 'units.post':prop['chart.units.post'],
1084
+ 'ylabels.count':prop['chart.xlabels.count']
1085
+ });
1086
+
1087
+
1088
+ this.max = this.scale2.max;
1089
+ this.min = this.scale2.min;
1090
+ }
1091
+
1092
+ if (prop['chart.scale.decimals'] == null && Number(this.max) == 1) {
1093
+ this.Set('chart.scale.decimals', 1);
1094
+ }
1095
+
1096
+ /**
1097
+ * This is here to facilitate sequential colors
1098
+ */
1099
+ var colorIdx = 0;
1100
+
1101
+ //
1102
+ // For grouped bars we need to calculate the number of bars
1103
+ //
1104
+ this.numbars = RG.arrayLinearize(this.data).length;
1105
+
1106
+
1107
+
1108
+
1109
+ /**
1110
+ * if the chart is adjustable fix the scale so that it doesn't change.
1111
+ *
1112
+ * It's here (after the scale generation) so that the max value can be
1113
+ * set to the maximum scale value)
1114
+ */
1115
+ if (prop['chart.adjustable'] && !prop['chart.xmax']) {
1116
+ this.set('chart.xmax', this.scale2.max);
1117
+ }
1118
+
1119
+
1120
+
1121
+ // Draw the 3d axes if necessary
1122
+ if (prop['chart.variant'] === '3d') {
1123
+ RG.draw3DAxes(this);
1124
+ }
1125
+
1126
+
1127
+
1128
+
1129
+
1130
+
1131
+ /**
1132
+ * The bars are drawn HERE
1133
+ */
1134
+ var graphwidth = (ca.width - this.gutterLeft - this.gutterRight);
1135
+ var halfwidth = graphwidth / 2;
1136
+
1137
+ for (i=(len=this.data.length-1); i>=0; --i) {
1138
+
1139
+ // Work out the width and height
1140
+ var width = ma.abs((this.data[i] / this.max) * graphwidth);
1141
+ var height = this.graphheight / this.data.length;
1142
+
1143
+ var orig_height = height;
1144
+
1145
+ var x = this.gutterLeft;
1146
+ var y = this.gutterTop + (i * height);
1147
+ var vmargin = prop['chart.vmargin'];
1148
+
1149
+ // Account for the Y axis being on the right hand side
1150
+ if (prop['chart.yaxispos'] === 'right') {
1151
+ x = ca.width - this.gutterRight - ma.abs(width);
1152
+ }
1153
+
1154
+ // Account for negative lengths - Some browsers (eg Chrome) don't like a negative value
1155
+ if (width < 0) {
1156
+ x -= width;
1157
+ width = ma.abs(width);
1158
+ }
1159
+
1160
+ /**
1161
+ * Turn on the shadow if need be
1162
+ */
1163
+ if (prop['chart.shadow']) {
1164
+ co.shadowColor = prop['chart.shadow.color'];
1165
+ co.shadowBlur = prop['chart.shadow.blur'];
1166
+ co.shadowOffsetX = prop['chart.shadow.offsetx'];
1167
+ co.shadowOffsetY = prop['chart.shadow.offsety'];
1168
+ }
1169
+
1170
+ /**
1171
+ * Draw the bar
1172
+ */
1173
+ co.beginPath();
1174
+
1175
+ // Standard (non-grouped and non-stacked) bars here
1176
+ if (typeof this.data[i] == 'number' || RG.isNull(this.data[i])) {
1177
+
1178
+ var barHeight = height - (2 * vmargin),
1179
+ barWidth = ((this.data[i] - prop['chart.xmin']) / (this.max - prop['chart.xmin'])) * this.graphwidth,
1180
+ barX = this.gutterLeft;
1181
+
1182
+ // Account for Y axis pos
1183
+ if (prop['chart.yaxispos'] == 'center') {
1184
+ barWidth /= 2;
1185
+ barX += halfwidth;
1186
+
1187
+ if (this.data[i] < 0) {
1188
+ barWidth = (ma.abs(this.data[i]) - prop['chart.xmin']) / (this.max - prop['chart.xmin']);
1189
+ barWidth = barWidth * (this.graphwidth / 2);
1190
+ barX = ((this.graphwidth / 2) + this.gutterLeft) - barWidth;
1191
+ }
1192
+
1193
+ } else if (prop['chart.yaxispos'] == 'right') {
1194
+
1195
+ barWidth = ma.abs(barWidth);
1196
+ barX = ca.width - this.gutterRight - barWidth;
1197
+
1198
+ }
1199
+
1200
+ // Set the fill color
1201
+ co.strokeStyle = prop['chart.strokestyle'];
1202
+ co.fillStyle = prop['chart.colors'][0];
1203
+
1204
+ // Sequential colors
1205
+ ++colorIdx;
1206
+ if (prop['chart.colors.sequential'] && typeof colorIdx === 'number') {
1207
+ if (prop['chart.colors'][this.numbars - colorIdx]) {
1208
+ co.fillStyle = prop['chart.colors'][this.numbars - colorIdx];
1209
+ } else {
1210
+ co.fillStyle = prop['chart.colors'][prop['chart.colors'].length - 1];
1211
+ }
1212
+ }
1213
+
1214
+
1215
+
1216
+
1217
+
1218
+
1219
+
1220
+
1221
+
1222
+
1223
+
1224
+
1225
+
1226
+
1227
+
1228
+
1229
+ co.strokeRect(barX, this.gutterTop + (i * height) + prop['chart.vmargin'], barWidth, barHeight);
1230
+ co.fillRect(barX, this.gutterTop + (i * height) + prop['chart.vmargin'], barWidth, barHeight);
1231
+
1232
+
1233
+
1234
+
1235
+
1236
+
1237
+
1238
+
1239
+
1240
+
1241
+
1242
+
1243
+
1244
+
1245
+
1246
+
1247
+
1248
+
1249
+
1250
+
1251
+
1252
+
1253
+
1254
+
1255
+ this.coords.push([
1256
+ barX,
1257
+ y + vmargin,
1258
+ barWidth,
1259
+ height - (2 * vmargin),
1260
+ co.fillStyle,
1261
+ this.data[i],
1262
+ true
1263
+ ]);
1264
+
1265
+
1266
+
1267
+
1268
+
1269
+
1270
+ // Draw the 3D effect using the coords that have just been stored
1271
+ if (prop['chart.variant'] === '3d' && typeof this.data[i] == 'number') {
1272
+
1273
+
1274
+ var prevStrokeStyle = co.strokeStyle,
1275
+ prevFillStyle = co.fillStyle;
1276
+
1277
+ /**
1278
+ * Turn off the shadow for the 3D bits
1279
+ */
1280
+ RG.noShadow(this);
1281
+
1282
+ // DRAW THE 3D BITS HERE
1283
+ var barX = barX,
1284
+ barY = y + vmargin,
1285
+ barW = barWidth,
1286
+ barH = height - (2 * vmargin),
1287
+ offsetX = prop['chart.variant.threed.offsetx'],
1288
+ offsetY = prop['chart.variant.threed.offsety'],
1289
+ value = this.data[i];
1290
+
1291
+
1292
+ pa2(
1293
+ co,
1294
+ [
1295
+ 'b',
1296
+ 'm', barX, barY,
1297
+ 'l', barX + offsetX - (prop['chart.yaxispos'] == 'left' && value < 0 ? offsetX : 0), barY - offsetY,
1298
+ 'l', barX + barW + offsetX - (prop['chart.yaxispos'] == 'center' && value < 0 ? offsetX : 0), barY - offsetY,
1299
+ 'l', barX + barW, barY,
1300
+ 'c',
1301
+ 's', co.strokeStyle,
1302
+ 'f', co.fillStyle,
1303
+ 'f','rgba(255,255,255,0.6)'//Fill again to lighten it
1304
+ ]
1305
+ );
1306
+
1307
+ if ( prop['chart.yaxispos'] !== 'right'
1308
+ && !(prop['chart.yaxispos'] === 'center' && value < 0)
1309
+ && value >= 0
1310
+ && !RG.isNull(value)
1311
+ ) {
1312
+
1313
+ pa2(
1314
+ co,
1315
+ [
1316
+ 'b',
1317
+ 'fs', prevFillStyle,
1318
+ 'm', barX + barW, barY,
1319
+ 'l', barX + barW + offsetX, barY - offsetY,
1320
+ 'l', barX + barW + offsetX, barY - offsetY + barH,
1321
+ 'l', barX + barW, barY + barH,
1322
+ 'c',
1323
+ 's', co.strokeStyle,
1324
+ 'f', prevFillStyle,
1325
+ 'f', 'rgba(0,0,0,0.25)'
1326
+ ]
1327
+ );
1328
+ }
1329
+
1330
+ }
1331
+
1332
+
1333
+
1334
+
1335
+
1336
+
1337
+ /**
1338
+ * Stacked bar chart
1339
+ */
1340
+ } else if (typeof(this.data[i]) == 'object' && prop['chart.grouping'] == 'stacked') {
1341
+
1342
+ if (prop['chart.yaxispos'] == 'center') {
1343
+ alert('[HBAR] You can\'t have a stacked chart with the Y axis in the center, change it to grouped');
1344
+ } else if (prop['chart.yaxispos'] == 'right') {
1345
+ var x = ca.width - this.gutterRight
1346
+ }
1347
+
1348
+ var barHeight = height - (2 * vmargin);
1349
+
1350
+ if (typeof this.coords2[i] == 'undefined') {
1351
+ this.coords2[i] = [];
1352
+ }
1353
+
1354
+ for (j=0; j<this.data[i].length; ++j) {
1355
+
1356
+ // The previous 3D segments would have turned the shadow off - so turn it back on
1357
+ if (prop['chart.shadow'] && prop['chart.variant'] === '3d') {
1358
+ co.shadowColor = prop['chart.shadow.color'];
1359
+ co.shadowBlur = prop['chart.shadow.blur'];
1360
+ co.shadowOffsetX = prop['chart.shadow.offsetx'];
1361
+ co.shadowOffsetY = prop['chart.shadow.offsety'];
1362
+ }
1363
+
1364
+ //
1365
+ // Ensure the number is positive
1366
+ //(even though having the X axis on the right implies a
1367
+ //negative value)
1368
+ //
1369
+ if (!RG.isNull(this.data[i][j])) this.data[i][j] = ma.abs(this.data[i][j]);
1370
+
1371
+
1372
+ var last = (j === (this.data[i].length - 1) );
1373
+
1374
+ // Set the fill/stroke colors
1375
+ co.strokeStyle = prop['chart.strokestyle'];
1376
+
1377
+ // Sequential colors
1378
+ ++colorIdx;
1379
+ if (prop['chart.colors.sequential'] && typeof colorIdx === 'number') {
1380
+ if (prop['chart.colors'][this.numbars - colorIdx]) {
1381
+ co.fillStyle = prop['chart.colors'][this.numbars - colorIdx];
1382
+ } else {
1383
+ co.fillStyle = prop['chart.colors'][prop['chart.colors'].length - 1];
1384
+ }
1385
+ } else if (prop['chart.colors'][j]) {
1386
+ co.fillStyle = prop['chart.colors'][j];
1387
+ }
1388
+
1389
+
1390
+ var width = (((this.data[i][j]) / (this.max))) * this.graphwidth;
1391
+ var totalWidth = (RG.arraySum(this.data[i]) / this.max) * this.graphwidth;
1392
+
1393
+ if (prop['chart.yaxispos'] === 'right') {
1394
+ x -= width;
1395
+ }
1396
+
1397
+
1398
+
1399
+ co.strokeRect(x, this.gutterTop + prop['chart.vmargin'] + (this.graphheight / this.data.length) * i, width, height - (2 * vmargin) );
1400
+ co.fillRect(x, this.gutterTop + prop['chart.vmargin'] + (this.graphheight / this.data.length) * i, width, height - (2 * vmargin) );
1401
+
1402
+
1403
+ /**
1404
+ * Store the coords for tooltips
1405
+ */
1406
+
1407
+ // The last property of this array is a boolean which tells you whether the value is the last or not
1408
+ this.coords.push([
1409
+ x,
1410
+ y + vmargin,
1411
+ width,
1412
+ height - (2 * vmargin),
1413
+ co.fillStyle,
1414
+ RG.array_sum(this.data[i]),
1415
+ j == (this.data[i].length - 1)
1416
+ ]);
1417
+
1418
+ this.coords2[i].push([
1419
+ x,
1420
+ y + vmargin,
1421
+ width,
1422
+ height - (2 * vmargin),
1423
+ co.fillStyle,
1424
+ RG.array_sum(this.data[i]),
1425
+ j == (this.data[i].length - 1)
1426
+ ]);
1427
+
1428
+
1429
+
1430
+
1431
+
1432
+
1433
+ // 3D effect
1434
+ if (prop['chart.variant'] === '3d') {
1435
+
1436
+ /**
1437
+ * Turn off the shadow for the 3D bits
1438
+ */
1439
+ RG.noShadow(this);
1440
+
1441
+ var prevStrokeStyle = co.strokeStyle,
1442
+ prevFillStyle = co.fillStyle;
1443
+
1444
+ // DRAW THE 3D BITS HERE
1445
+ var barX = x,
1446
+ barY = y + vmargin,
1447
+ barW = width,
1448
+ barH = height - (2 * vmargin),
1449
+ offsetX = prop['chart.variant.threed.offsetx'],
1450
+ offsetY = prop['chart.variant.threed.offsety'],
1451
+ value = this.data[i][j];
1452
+
1453
+ if (!RG.isNull(value)) {
1454
+ pa2(
1455
+ co,
1456
+ [
1457
+ 'b',
1458
+ 'm', barX, barY,
1459
+ 'l', barX + offsetX, barY - offsetY,
1460
+ 'l', barX + barW + offsetX, barY - offsetY,
1461
+ 'l', barX + barW, barY,
1462
+ 'c',
1463
+ 's', co.strokeStyle,
1464
+ 'f', co.fillStyle,
1465
+ 'f','rgba(255,255,255,0.6)'//Fill again to lighten it
1466
+ ]
1467
+ );
1468
+ }
1469
+
1470
+ if ( prop['chart.yaxispos'] !== 'right'
1471
+ && !(prop['chart.yaxispos'] === 'center' && value < 0)
1472
+ && !RG.isNull(value)
1473
+ ) {
1474
+
1475
+ pa2(
1476
+ co,
1477
+ [
1478
+ 'fs', prevFillStyle,
1479
+ 'b',
1480
+ 'm', barX + barW, barY,
1481
+ 'l', barX + barW + offsetX, barY - offsetY,
1482
+ 'l', barX + barW + offsetX, barY - offsetY + barH,
1483
+ 'l', barX + barW, barY + barH,
1484
+ 'c',
1485
+ 's', co.strokeStyle,
1486
+ 'f', prevFillStyle,
1487
+ 'f', 'rgba(0,0,0,0.25)'
1488
+ ]
1489
+ );
1490
+ }
1491
+
1492
+ co.beginPath();
1493
+ co.strokeStyle = prevStrokeStyle;
1494
+ co.fillStyle = prevFillStyle;
1495
+ }
1496
+
1497
+
1498
+
1499
+
1500
+
1501
+
1502
+ if (prop['chart.yaxispos'] !== 'right') {
1503
+ x += width;
1504
+ }
1505
+ }
1506
+
1507
+
1508
+
1509
+
1510
+
1511
+
1512
+
1513
+
1514
+ /**
1515
+ * A grouped bar chart
1516
+ */
1517
+ } else if (typeof(this.data[i]) == 'object' && prop['chart.grouping'] == 'grouped') {
1518
+
1519
+ var vmarginGrouped = prop['chart.vmargin.grouped'];
1520
+ var individualBarHeight = ((height - (2 * vmargin) - ((this.data[i].length - 1) * vmarginGrouped)) / this.data[i].length)
1521
+
1522
+ if (typeof this.coords2[i] == 'undefined') {
1523
+ this.coords2[i] = [];
1524
+ }
1525
+
1526
+ for (j=(this.data[i].length - 1); j>=0; --j) {
1527
+
1528
+ /**
1529
+ * Turn on the shadow if need be
1530
+ */
1531
+ if (prop['chart.shadow']) {
1532
+ RG.setShadow(this, prop['chart.shadow.color'], prop['chart.shadow.offsetx'], prop['chart.shadow.offsety'], prop['chart.shadow.blur']);
1533
+ }
1534
+
1535
+ // Set the fill/stroke colors
1536
+ co.strokeStyle = prop['chart.strokestyle'];
1537
+
1538
+ // Sequential colors
1539
+ ++colorIdx;
1540
+ if (prop['chart.colors.sequential'] && typeof colorIdx === 'number') {
1541
+ if (prop['chart.colors'][this.numbars - colorIdx]) {
1542
+ co.fillStyle = prop['chart.colors'][this.numbars - colorIdx];
1543
+ } else {
1544
+ co.fillStyle = prop['chart.colors'][prop['chart.colors'].length - 1];
1545
+ }
1546
+ } else if (prop['chart.colors'][j]) {
1547
+ co.fillStyle = prop['chart.colors'][j];
1548
+ }
1549
+
1550
+
1551
+
1552
+ var startY = this.gutterTop + (height * i) + (individualBarHeight * j) + vmargin + (vmarginGrouped * j);
1553
+ var width = ((this.data[i][j] - prop['chart.xmin']) / (this.max - prop['chart.xmin'])) * (ca.width - this.gutterLeft - this.gutterRight );
1554
+ var startX = this.gutterLeft;
1555
+
1556
+
1557
+
1558
+ // Account for the Y axis being in the middle
1559
+ if (prop['chart.yaxispos'] == 'center') {
1560
+ width /= 2;
1561
+ startX += halfwidth;
1562
+
1563
+ // Account for the Y axis being on the right
1564
+ } else if (prop['chart.yaxispos'] == 'right') {
1565
+ width = ma.abs(width);
1566
+ startX = ca.width - this.gutterRight - ma.abs(width);;
1567
+ }
1568
+
1569
+ if (width < 0) {
1570
+ startX += width;
1571
+ width *= -1;
1572
+ }
1573
+
1574
+ co.strokeRect(startX, startY, width, individualBarHeight);
1575
+ co.fillRect(startX, startY, width, individualBarHeight);
1576
+
1577
+
1578
+
1579
+
1580
+
1581
+
1582
+ this.coords.push([
1583
+ startX,
1584
+ startY,
1585
+ width,
1586
+ individualBarHeight,
1587
+ co.fillStyle,
1588
+ this.data[i][j],
1589
+ true
1590
+ ]);
1591
+
1592
+ this.coords2[i].push([
1593
+ startX,
1594
+ startY,
1595
+ width,
1596
+ individualBarHeight,
1597
+ co.fillStyle,
1598
+ this.data[i][j],
1599
+ true
1600
+ ]);
1601
+
1602
+
1603
+
1604
+
1605
+
1606
+
1607
+
1608
+
1609
+
1610
+
1611
+
1612
+
1613
+ // 3D effect
1614
+ if (prop['chart.variant'] === '3d') {
1615
+
1616
+ /**
1617
+ * Turn off the shadow for the 3D bits
1618
+ */
1619
+ RG.noShadow(this);
1620
+
1621
+ var prevStrokeStyle = co.strokeStyle,
1622
+ prevFillStyle = co.fillStyle;
1623
+
1624
+ // DRAW THE 3D BITS HERE
1625
+ var barX = startX,
1626
+ barY = startY,
1627
+ barW = width,
1628
+ barH = individualBarHeight,
1629
+ offsetX = prop['chart.variant.threed.offsetx'],
1630
+ offsetY = prop['chart.variant.threed.offsety'],
1631
+ value = this.data[i][j];
1632
+
1633
+ pa2(
1634
+ co,
1635
+ [
1636
+ 'b',
1637
+ 'm', barX, barY,
1638
+ 'l', barX + offsetX, barY - offsetY,
1639
+ 'l', barX + barW + offsetX - (value < 0 ? offsetX : 0), barY - offsetY,
1640
+ 'l', barX + barW, barY,
1641
+ 'c',
1642
+ 's', co.strokeStyle,
1643
+ 'f', co.fillStyle,
1644
+ 'f','rgba(255,255,255,0.6)'//Fill again to lighten it
1645
+ ]
1646
+ );
1647
+
1648
+ if ( prop['chart.yaxispos'] !== 'right'
1649
+ && !(prop['chart.yaxispos'] === 'center' && value < 0)
1650
+ && value >= 0
1651
+ && !RG.isNull(value)
1652
+ ) {
1653
+
1654
+ pa2(
1655
+ co,
1656
+ [
1657
+ 'fs', prevFillStyle,
1658
+ 'b',
1659
+ 'm', barX + barW, barY,
1660
+ 'l', barX + barW + offsetX, barY - offsetY,
1661
+ 'l', barX + barW + offsetX, barY - offsetY + barH,
1662
+ 'l', barX + barW, barY + barH,
1663
+ 'c',
1664
+ 's', co.strokeStyle,
1665
+ 'f', prevFillStyle,
1666
+ 'f', 'rgba(0,0,0,0.25)'
1667
+ ]
1668
+ );
1669
+ }
1670
+
1671
+
1672
+
1673
+
1674
+
1675
+ co.beginPath();
1676
+ co.strokeStyle = prevStrokeStyle;
1677
+ co.fillStyle = prevFillStyle;
1678
+ }
1679
+
1680
+
1681
+
1682
+
1683
+
1684
+
1685
+ }
1686
+
1687
+ startY += vmargin;
1688
+ }
1689
+
1690
+ co.closePath();
1691
+ }
1692
+
1693
+ co.stroke();
1694
+ co.fill();
1695
+
1696
+ // Under certain circumstances we can cover the shadow
1697
+ // overspill with a white rectangle
1698
+ if (prop['chart,yaxispos'] === 'right') {
1699
+ pa2(co, 'cr % % % %',
1700
+ ca.width - this.gutterRight + prop['chart.variant.threed.offsetx'],
1701
+ '0',
1702
+ this.gutterRight,
1703
+ ca.height
1704
+ );
1705
+ }
1706
+
1707
+
1708
+
1709
+
1710
+
1711
+
1712
+ // Draw the 3d axes AGAIN if the Y axis is on the right
1713
+ if ( prop['chart.yaxispos'] === 'right'
1714
+ && prop['chart.variant'] === '3d'
1715
+ ) {
1716
+ RG.draw3DYAxis(this);
1717
+ }
1718
+
1719
+ /**
1720
+ * Now the bars are stroke()ed, turn off the shadow
1721
+ */
1722
+ RG.noShadow(this);
1723
+
1724
+
1725
+ //
1726
+ // Reverse the coords arrays as the bars are drawn from the borrom up now
1727
+ //
1728
+ this.coords = RG.arrayReverse(this.coords);
1729
+
1730
+ if (prop['chart.grouping'] === 'grouped') {
1731
+ for (var i=0; i<this.coords2.length; ++i) {
1732
+ this.coords2[i] = RG.arrayReverse(this.coords2[i]);
1733
+ }
1734
+ }
1735
+
1736
+
1737
+ this.redrawBars();
1738
+ };
1739
+
1740
+
1741
+
1742
+
1743
+ /**
1744
+ * This function goes over the bars after they been drawn, so that upwards shadows are underneath the bars
1745
+ */
1746
+ this.redrawBars =
1747
+ this.RedrawBars = function ()
1748
+ {
1749
+ if (prop['chart.noredraw']) {
1750
+ return;
1751
+ }
1752
+
1753
+ var coords = this.coords;
1754
+
1755
+ var font = prop['chart.text.font'],
1756
+ size = prop['chart.text.size'],
1757
+ color = prop['chart.text.color'];
1758
+
1759
+ RG.noShadow(this);
1760
+ co.strokeStyle = prop['chart.strokestyle'];
1761
+
1762
+ for (var i=0; i<coords.length; ++i) {
1763
+
1764
+ if (prop['chart.shadow']) {
1765
+
1766
+ pa2(co, 'b lw % r % % % % s % f %',
1767
+ prop['chart.linewidth'],
1768
+ coords[i][0],
1769
+ coords[i][1],
1770
+ coords[i][2],
1771
+ coords[i][3],
1772
+ prop['chart.strokestyle'],
1773
+ coords[i][4]
1774
+ );
1775
+ }
1776
+
1777
+ /**
1778
+ * Draw labels "above" the bar
1779
+ */
1780
+ var halign = 'left';
1781
+ if (prop['chart.labels.above'] && coords[i][6]) {
1782
+
1783
+ var border = (coords[i][0] + coords[i][2] + 7 + co.measureText(prop['chart.labels.above.units.pre'] + this.coords[i][5] + prop['chart.labels.above.units.post']).width) > ca.width ? true : false,
1784
+ text = RG.numberFormat(this, (this.coords[i][5]).toFixed(prop['chart.labels.above.decimals']), prop['chart.labels.above.units.pre'], prop['chart.labels.above.units.post']);
1785
+
1786
+ RG.noShadow(this);
1787
+
1788
+ /**
1789
+ * Default to the value - then check for specific labels
1790
+ */
1791
+
1792
+
1793
+ if (typeof prop['chart.labels.above.specific'] === 'object' && prop['chart.labels.above.specific'] && prop['chart.labels.above.specific'][i]) {
1794
+ text = prop['chart.labels.above.specific'][i];
1795
+ }
1796
+
1797
+ var x = coords[i][0] + coords[i][2] + 5;
1798
+ var y = coords[i][1] + (coords[i][3] / 2);
1799
+
1800
+ if (prop['chart.yaxispos'] === 'right') {
1801
+ x = coords[i][0] - 5;
1802
+ halign = 'right';
1803
+ } else if (prop['chart.yaxispos'] === 'center' && this.data_arr[i] < 0) {
1804
+ x = coords[i][0] - 5;
1805
+ halign = 'right';
1806
+ }
1807
+
1808
+ RG.text2(this, {
1809
+ font: typeof prop['chart.labels.above.font'] === 'string' ? prop['chart.labels.above.font'] : font,
1810
+ size: typeof prop['chart.labels.above.size'] === 'number' ? prop['chart.labels.above.size'] : size,
1811
+ color: typeof prop['chart.labels.above.color'] ==='string' ? prop['chart.labels.above.color'] : color,
1812
+ x: x,
1813
+ y: y,
1814
+ bold: prop['chart.labels.above.bold'],
1815
+ italic: prop['chart.labels.above.italic'],
1816
+ text: text,
1817
+ valign: 'center',
1818
+ halign: halign,
1819
+ tag: 'labels.above'
1820
+ });
1821
+ }
1822
+ }
1823
+ };
1824
+
1825
+
1826
+
1827
+
1828
+ /**
1829
+ * This function can be used to get the appropriate bar information (if any)
1830
+ *
1831
+ * @param e Event object
1832
+ * @return Appriate bar information (if any)
1833
+ */
1834
+ this.getShape =
1835
+ this.getBar = function (e)
1836
+ {
1837
+ var mouseXY = RG.getMouseXY(e);
1838
+
1839
+ /**
1840
+ * Loop through the bars determining if the mouse is over a bar
1841
+ */
1842
+ for (var i=0,len=this.coords.length; i<len; i++) {
1843
+
1844
+ var mouseX = mouseXY[0], // In relation to the canvas
1845
+ mouseY = mouseXY[1], // In relation to the canvas
1846
+ left = this.coords[i][0],
1847
+ top = this.coords[i][1],
1848
+ width = this.coords[i][2],
1849
+ height = this.coords[i][3],
1850
+ idx = i;
1851
+
1852
+
1853
+
1854
+ // Recreate the path/rectangle so that it can be tested
1855
+ // ** DO NOT STROKE OR FILL IT **
1856
+ pa2(co,['b','r',left,top,width,height]);
1857
+
1858
+ if (co.isPointInPath(mouseX, mouseY)) {
1859
+
1860
+ var tooltip = RG.parseTooltipText(prop['chart.tooltips'], i);
1861
+
1862
+ return {
1863
+ 0: this, 'object': this,
1864
+ 1: left, 'x': left,
1865
+ 2: top, 'y': top,
1866
+ 3: width, 'width': width,
1867
+ 4: height, 'height': height,
1868
+ 5: idx, 'index': idx,
1869
+ 'tooltip': tooltip
1870
+ };
1871
+ }
1872
+ }
1873
+ };
1874
+
1875
+
1876
+
1877
+
1878
+ /**
1879
+ * When you click on the chart, this method can return the X value at that point. It works for any point on the
1880
+ * chart (that is inside the gutters) - not just points within the Bars.
1881
+ *
1882
+ * @param object e The event object
1883
+ */
1884
+ this.getValue = function (arg)
1885
+ {
1886
+ if (arg.length == 2) {
1887
+ var mouseX = arg[0];
1888
+ var mouseY = arg[1];
1889
+ } else {
1890
+ var mouseCoords = RG.getMouseXY(arg);
1891
+ var mouseX = mouseCoords[0];
1892
+ var mouseY = mouseCoords[1];
1893
+ }
1894
+
1895
+ if ( mouseY < this.gutterTop
1896
+ || mouseY > (ca.height - this.gutterBottom)
1897
+ || mouseX < this.gutterLeft
1898
+ || mouseX > (ca.width - this.gutterRight)
1899
+ ) {
1900
+ return null;
1901
+ }
1902
+
1903
+
1904
+
1905
+
1906
+
1907
+ if (prop['chart.yaxispos'] == 'center') {
1908
+ var value = ((mouseX - this.gutterLeft) / (this.graphwidth / 2)) * (this.max - prop['chart.xmin']);
1909
+ value = value - this.max
1910
+
1911
+ // Special case if xmin is defined
1912
+ if (prop['chart.xmin'] > 0) {
1913
+ value = ((mouseX - this.gutterLeft - (this.graphwidth / 2)) / (this.graphwidth / 2)) * (this.max - prop['chart.xmin']);
1914
+ value += prop['chart.xmin'];
1915
+
1916
+ if (mouseX < (this.gutterLeft + (this.graphwidth / 2))) {
1917
+ value -= (2 * prop['chart.xmin']);
1918
+ }
1919
+ }
1920
+
1921
+
1922
+ // TODO This needs fixing
1923
+ } else if (prop['chart.yaxispos'] == 'right') {
1924
+ var value = ((mouseX - this.gutterLeft) / this.graphwidth) * (this.scale2.max - prop['chart.xmin']);
1925
+ value = this.scale2.max - value;
1926
+
1927
+ } else {
1928
+ var value = ((mouseX - this.gutterLeft) / this.graphwidth) * (this.scale2.max - prop['chart.xmin']);
1929
+ value += prop['chart.xmin'];
1930
+ }
1931
+
1932
+
1933
+
1934
+
1935
+
1936
+
1937
+ return value;
1938
+ };
1939
+
1940
+
1941
+
1942
+
1943
+ /**
1944
+ * Each object type has its own Highlight() function which highlights the appropriate shape
1945
+ *
1946
+ * @param object shape The shape to highlight
1947
+ */
1948
+ this.highlight =
1949
+ this.Highlight = function (shape)
1950
+ {
1951
+ if (typeof prop['chart.highlight.style'] === 'function') {
1952
+ (prop['chart.highlight.style'])(shape);
1953
+ } else {
1954
+ RG.Highlight.Rect(this, shape);
1955
+ }
1956
+ };
1957
+
1958
+
1959
+
1960
+
1961
+ /**
1962
+ * The getObjectByXY() worker method. Don't call this call:
1963
+ *
1964
+ * RG.ObjectRegistry.getObjectByXY(e)
1965
+ *
1966
+ * @param object e The event object
1967
+ */
1968
+ this.getObjectByXY = function (e)
1969
+ {
1970
+ var mouseXY = RG.getMouseXY(e);
1971
+
1972
+ // Adjust the mouse Y coordinate for when the bar chart is
1973
+ // a 3D variant
1974
+ if (prop['chart.variant'] === '3d') {
1975
+ var adjustment = prop['chart.variant.threed.angle'] * mouseXY[0];
1976
+ mouseXY[1] -= adjustment;
1977
+ }
1978
+
1979
+
1980
+ if (
1981
+ mouseXY[0] >= this.gutterLeft
1982
+ && mouseXY[0] <= (ca.width - this.gutterRight)
1983
+ && mouseXY[1] >= this.gutterTop
1984
+ && mouseXY[1] <= (ca.height - this.gutterBottom)
1985
+ ) {
1986
+
1987
+ return this;
1988
+ }
1989
+ };
1990
+
1991
+
1992
+
1993
+
1994
+ /**
1995
+ * This function positions a tooltip when it is displayed
1996
+ *
1997
+ * @param obj object The chart object
1998
+ * @param int x The X coordinate specified for the tooltip
1999
+ * @param int y The Y coordinate specified for the tooltip
2000
+ * @param objec tooltip The tooltips DIV element
2001
+ *
2002
+ this.positionTooltip = function (obj, x, y, tooltip, idx)
2003
+ {
2004
+ var coordX = obj.coords[tooltip.__index__][0],
2005
+ coordY = obj.coords[tooltip.__index__][1],
2006
+ coordW = obj.coords[tooltip.__index__][2],
2007
+ coordH = obj.coords[tooltip.__index__][3],
2008
+ canvasXY = RG.getCanvasXY(obj.canvas),
2009
+ gutterLeft = obj.gutterLeft,
2010
+ gutterTop = obj.gutterTop,
2011
+ width = tooltip.offsetWidth,
2012
+ height = tooltip.offsetHeight,
2013
+ mouseXY = RG.getMouseXY(window.event);
2014
+
2015
+ // If the chart is a 3D version the tooltip Y position needs this
2016
+ // adjustment
2017
+ if (prop['chart.variant'] === '3d' && coordW) {
2018
+ var adjustment = (prop['chart.variant.threed.angle'] * ((coordX + coordW) / 2));
2019
+ }
2020
+
2021
+
2022
+
2023
+ // Set the top position
2024
+ tooltip.style.left = 0;
2025
+ tooltip.style.top = window.event.pageY - height - 5 + 'px';
2026
+
2027
+ // By default any overflow is hidden
2028
+ tooltip.style.overflow = '';
2029
+
2030
+ // Reposition the tooltip if at the edges:
2031
+
2032
+ // LEFT edge
2033
+ if (canvasXY[0] + mouseXY[0] - (width / 2) < 0) {
2034
+ tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.1) + 'px';
2035
+
2036
+ // RIGHT edge
2037
+ } else if (canvasXY[0] + mouseXY[0] + (width / 2) > doc.body.offsetWidth) {
2038
+ tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.9) + 'px';
2039
+
2040
+ // Default positioning - CENTERED
2041
+ } else {
2042
+ tooltip.style.left = canvasXY[0] + mouseXY[0] - (width / 2) + 'px';
2043
+ }
2044
+ };*/
2045
+
2046
+
2047
+
2048
+
2049
+ /**
2050
+ * Returns the appropriate Y coord for the given value
2051
+ *
2052
+ * @param number value The value to get the coord for
2053
+ */
2054
+ this.getXCoord = function (value)
2055
+ {
2056
+
2057
+ if (prop['chart.yaxispos'] == 'center') {
2058
+
2059
+ // Range checking
2060
+ if (value > this.max || value < (-1 * this.max)) {
2061
+ return null;
2062
+ }
2063
+
2064
+ var width = (ca.width - prop['chart.gutter.left'] - prop['chart.gutter.right']) / 2;
2065
+ var coord = (((value - prop['chart.xmin']) / (this.max - prop['chart.xmin'])) * width) + width;
2066
+
2067
+ coord = prop['chart.gutter.left'] + coord;
2068
+ } else {
2069
+
2070
+ // Range checking
2071
+ if (value > this.max || value < 0) {
2072
+ return null;
2073
+ }
2074
+
2075
+ var width = ca.width - prop['chart.gutter.left'] - prop['chart.gutter.right'];
2076
+ var coord = ((value - prop['chart.xmin']) / (this.max - prop['chart.xmin'])) * width;
2077
+
2078
+ coord = prop['chart.gutter.left'] + coord;
2079
+ }
2080
+
2081
+ return coord;
2082
+ };
2083
+
2084
+
2085
+
2086
+
2087
+ /**
2088
+ *
2089
+ */
2090
+ this.parseColors = function ()
2091
+ {
2092
+ // Save the original colors so that they can be restored when the canvas is reset
2093
+ if (this.original_colors.length === 0) {
2094
+ //this.original_colors['chart.'] = RG.array_clone(prop['chart.']);
2095
+ this.original_colors['chart.colors'] = RG.array_clone(prop['chart.colors']);
2096
+ this.original_colors['chart.background.grid.color'] = RG.array_clone(prop['chart.background.grid.color']);
2097
+ this.original_colors['chart.background.color'] = RG.array_clone(prop['chart.background.color']);
2098
+ this.original_colors['chart.background.barcolor1'] = RG.array_clone(prop['chart.background.barcolor1']);
2099
+ this.original_colors['chart.background.barcolor2'] = RG.array_clone(prop['chart.background.barcolor2']);
2100
+ this.original_colors['chart.text.color'] = RG.array_clone(prop['chart.text.color']);
2101
+ this.original_colors['chart.labels.colors'] = RG.array_clone(prop['chart.labels.colors']);
2102
+ this.original_colors['chart.strokestyle'] = RG.array_clone(prop['chart.strokestyle']);
2103
+ this.original_colors['chart.axis.color'] = RG.array_clone(prop['chart.axis.color']);
2104
+ this.original_colors['chart.highlight.fill'] = RG.array_clone(prop['chart.highlight.fill']);
2105
+ this.original_colors['chart.highlight.stroke'] = RG.array_clone(prop['chart.highlight.stroke']);
2106
+
2107
+ }
2108
+
2109
+ var colors = prop['chart.colors'];
2110
+
2111
+ for (var i=0; i<colors.length; ++i) {
2112
+ colors[i] = this.parseSingleColorForGradient(colors[i]);
2113
+ }
2114
+
2115
+ prop['chart.background.grid.color'] = this.parseSingleColorForGradient(prop['chart.background.grid.color']);
2116
+ prop['chart.background.color'] = this.parseSingleColorForGradient(prop['chart.background.color']);
2117
+ prop['chart.background.barcolor1'] = this.parseSingleColorForGradient(prop['chart.background.barcolor1']);
2118
+ prop['chart.background.barcolor2'] = this.parseSingleColorForGradient(prop['chart.background.barcolor2']);
2119
+ prop['chart.text.color'] = this.parseSingleColorForGradient(prop['chart.text.color']);
2120
+ prop['chart.labels.colors'] = this.parseSingleColorForGradient(prop['chart.labels.colors']);
2121
+ prop['chart.strokestyle'] = this.parseSingleColorForGradient(prop['chart.strokestyle']);
2122
+ prop['chart.axis.color'] = this.parseSingleColorForGradient(prop['chart.axis.color']);
2123
+ prop['chart.highlight.fill'] = this.parseSingleColorForGradient(prop['chart.highlight.fill']);
2124
+ prop['chart.highlight.stroke'] = this.parseSingleColorForGradient(prop['chart.highlight.stroke']);
2125
+ };
2126
+
2127
+
2128
+
2129
+
2130
+ /**
2131
+ * Use this function to reset the object to the post-constructor state. Eg reset colors if
2132
+ * need be etc
2133
+ */
2134
+ this.reset = function ()
2135
+ {
2136
+ };
2137
+
2138
+
2139
+
2140
+ /**
2141
+ * This parses a single color value
2142
+ */
2143
+ this.parseSingleColorForGradient = function (color)
2144
+ {
2145
+ if (!color || typeof(color) != 'string') {
2146
+ return color;
2147
+ }
2148
+
2149
+ if (color.match(/^gradient\((.*)\)$/i)) {
2150
+
2151
+ var parts = RegExp.$1.split(':');
2152
+
2153
+ if (prop['chart.yaxispos'] === 'right') {
2154
+ parts = RG.arrayReverse(parts);
2155
+ }
2156
+
2157
+ // Create the gradient
2158
+ var grad = co.createLinearGradient(prop['chart.gutter.left'],0,ca.width - prop['chart.gutter.right'],0);
2159
+
2160
+ var diff = 1 / (parts.length - 1);
2161
+
2162
+ grad.addColorStop(0, RG.trim(parts[0]));
2163
+
2164
+ for (var j=1; j<parts.length; ++j) {
2165
+ grad.addColorStop(j * diff, RG.trim(parts[j]));
2166
+ }
2167
+ }
2168
+
2169
+ return grad ? grad : color;
2170
+ };
2171
+
2172
+
2173
+
2174
+
2175
+ /**
2176
+ * This function handles highlighting an entire data-series for the interactive
2177
+ * key
2178
+ *
2179
+ * @param int index The index of the data series to be highlighted
2180
+ */
2181
+ this.interactiveKeyHighlight = function (index)
2182
+ {
2183
+ var obj = this;
2184
+
2185
+ this.coords2.forEach(function (value, idx, arr)
2186
+ {
2187
+ var shape = obj.coords2[idx][index]
2188
+ var pre_linewidth = co.lineWidth;
2189
+ co.lineWidth = 2;
2190
+ co.fillStyle = prop['chart.key.interactive.highlight.chart.fill'];
2191
+ co.strokeStyle = prop['chart.key.interactive.highlight.chart.stroke'];
2192
+ co.fillRect(shape[0], shape[1], shape[2], shape[3]);
2193
+ co.strokeRect(shape[0], shape[1], shape[2], shape[3]);
2194
+
2195
+ // Reset the lineWidth
2196
+ co.lineWidth = pre_linewidth;
2197
+ });
2198
+ };
2199
+
2200
+
2201
+
2202
+
2203
+ /**
2204
+ * Using a function to add events makes it easier to facilitate method chaining
2205
+ *
2206
+ * @param string type The type of even to add
2207
+ * @param function func
2208
+ */
2209
+ this.on = function (type, func)
2210
+ {
2211
+ if (type.substr(0,2) !== 'on') {
2212
+ type = 'on' + type;
2213
+ }
2214
+
2215
+ if (typeof this[type] !== 'function') {
2216
+ this[type] = func;
2217
+ } else {
2218
+ RG.addCustomEventListener(this, type, func);
2219
+ }
2220
+
2221
+ return this;
2222
+ };
2223
+
2224
+
2225
+
2226
+
2227
+ /**
2228
+ * This function runs once only
2229
+ * (put at the end of the file (before any effects))
2230
+ */
2231
+ this.firstDrawFunc = function ()
2232
+ {
2233
+ };
2234
+
2235
+
2236
+
2237
+
2238
+ /**
2239
+ * This retrives the bar based on the X coordinate only.
2240
+ *
2241
+ * @param object e The event object
2242
+ * @param object OPTIONAL You can pass in the bar object instead of the
2243
+ * function using "this"
2244
+ */
2245
+ this.getShapeByY = function (e)
2246
+ {
2247
+ var mouseXY = RG.getMouseXY(e);
2248
+
2249
+
2250
+ // This facilitates you being able to pass in the bar object as a parameter instead of
2251
+ // the function getting it from itself
2252
+ var obj = arguments[1] ? arguments[1] : this;
2253
+
2254
+
2255
+ /**
2256
+ * Loop through the bars determining if the mouse is over a bar
2257
+ */
2258
+ for (var i=0,len=obj.coords.length; i<len; i++) {
2259
+
2260
+ if (obj.coords[i].length == 0) {
2261
+ continue;
2262
+ }
2263
+
2264
+ var mouseX = mouseXY[0],
2265
+ mouseY = mouseXY[1],
2266
+ left = obj.coords[i][0],
2267
+ top = obj.coords[i][1],
2268
+ width = obj.coords[i][2],
2269
+ height = obj.coords[i][3];
2270
+
2271
+ if (mouseY >= top && mouseY <= (top + height)) {
2272
+
2273
+ if (prop['chart.tooltips']) {
2274
+ var tooltip = RG.parseTooltipText ? RG.parseTooltipText(prop['chart.tooltips'], i) : prop['chart.tooltips'][i];
2275
+ }
2276
+
2277
+ return {
2278
+ 0: obj, object: obj,
2279
+ 1: left, x: left,
2280
+ 2: top, y: top,
2281
+ 3: width, width: width,
2282
+ 4: height, height: height,
2283
+ 5: i, index: i,
2284
+ tooltip: tooltip
2285
+ };
2286
+ }
2287
+ }
2288
+
2289
+ return null;
2290
+ };
2291
+
2292
+
2293
+
2294
+
2295
+ /**
2296
+ * This method handles the adjusting calculation for when the mouse is moved
2297
+ *
2298
+ * @param object e The event object
2299
+ */
2300
+ this.adjusting_mousemove =
2301
+ this.Adjusting_mousemove = function (e)
2302
+ {
2303
+ /**
2304
+ * Handle adjusting for the Bar
2305
+ */
2306
+ if (prop['chart.adjustable'] && RG.Registry.get('chart.adjusting') && RG.Registry.get('chart.adjusting').uid == this.uid) {
2307
+
2308
+ // Rounding the value to the given number of decimals make the chart step
2309
+ var value = Number(this.getValue(e)),
2310
+ shape = RG.Registry.get('chart.adjusting.shape');
2311
+
2312
+ if (shape) {
2313
+
2314
+ RG.Registry.Set('chart.adjusting.shape', shape);
2315
+
2316
+ if (this.stackedOrGrouped && prop['chart.grouping'] == 'grouped') {
2317
+
2318
+ var indexes = RG.sequentialIndexToGrouped(shape['index'], this.data);
2319
+
2320
+ if (typeof this.data[indexes[0]] == 'number') {
2321
+ this.data[indexes[0]] = Number(value);
2322
+ } else if (!RG.is_null(this.data[indexes[0]])) {
2323
+ this.data[indexes[0]][indexes[1]] = Number(value);
2324
+ }
2325
+ } else if (typeof this.data[shape['index']] == 'number') {
2326
+
2327
+ this.data[shape['index']] = Number(value);
2328
+ }
2329
+
2330
+ RG.redrawCanvas(e.target);
2331
+ RG.fireCustomEvent(this, 'onadjust');
2332
+ }
2333
+ }
2334
+ };
2335
+
2336
+
2337
+
2338
+
2339
+ /**
2340
+ * Grow
2341
+ *
2342
+ * The HBar chart Grow effect gradually increases the values of the bars
2343
+ *
2344
+ * @param object OPTIONAL Options for the effect. You can pass frames here
2345
+ * @param function OPTIONAL A callback function
2346
+ */
2347
+ this.grow = function ()
2348
+ {
2349
+ var obj = this,
2350
+ opt = arguments[0] || {},
2351
+ frames = opt.frames || 30,
2352
+ frame = 0,
2353
+ callback = arguments[1] || function () {},
2354
+ labelsAbove = prop['chart.labels.above'];
2355
+
2356
+ this.set('labelsAbove', false);
2357
+
2358
+
2359
+ // Save the data
2360
+ obj.original_data = RG.arrayClone(obj.data);
2361
+
2362
+
2363
+ // Stop the scale from changing by setting chart.ymax (if it's not already set)
2364
+ if (prop['chart.xmax'] == 0) {
2365
+
2366
+ var xmax = 0;
2367
+
2368
+ for (var i=0; i<obj.data.length; ++i) {
2369
+ if (RG.isArray(obj.data[i]) && prop['chart.grouping'] == 'stacked') {
2370
+ xmax = ma.max(xmax, RG.arraySum(obj.data[i]));
2371
+ } else if (RG.isArray(obj.data[i]) && prop['chart.grouping'] == 'grouped') {
2372
+ xmax = ma.max(xmax, RG.arrayMax(obj.data[i]));
2373
+ } else {
2374
+ xmax = ma.max(xmax, ma.abs(RG.arrayMax(obj.data[i])));
2375
+ }
2376
+ }
2377
+
2378
+ var scale2 = RG.getScale2(obj, {'max':xmax});
2379
+ obj.Set('chart.xmax', scale2.max);
2380
+ }
2381
+
2382
+ function iterator ()
2383
+ {
2384
+ // Alter the Bar chart data depending on the frame
2385
+ for (var j=0,len=obj.original_data.length; j<len; ++j) {
2386
+
2387
+ // This stops the animation from being completely linear
2388
+ var easingFactor = RG.Effects.getEasingMultiplier(frames, frame);
2389
+
2390
+ if (typeof obj.data[j] === 'object' && obj.data[j]) {
2391
+ for (var k=0,len2=obj.data[j].length; k<len2; ++k) {
2392
+ obj.data[j][k] = RG.isNull(obj.data[j][k]) ? null : obj.original_data[j][k] * easingFactor;
2393
+ }
2394
+ } else {
2395
+ obj.data[j] = RG.isNull(obj.data[j]) ? null : obj.original_data[j] * easingFactor;
2396
+ }
2397
+ }
2398
+
2399
+
2400
+
2401
+ RG.redrawCanvas(obj.canvas);
2402
+
2403
+ if (frame < frames) {
2404
+ frame += 1;
2405
+ RG.Effects.updateCanvas(iterator);
2406
+ } else {
2407
+
2408
+ if (labelsAbove) {
2409
+ obj.set('labelsAbove', true);
2410
+ RG.redraw();
2411
+ }
2412
+
2413
+ callback(obj);
2414
+ }
2415
+ }
2416
+
2417
+ iterator();
2418
+
2419
+ return this;
2420
+ };
2421
+
2422
+
2423
+
2424
+
2425
+ /**
2426
+ * (new) Bar chart Wave effect. This is a rewrite that should be smoother
2427
+ * because it just uses a single loop and not setTimeout
2428
+ *
2429
+ * @param object OPTIONAL An object map of options. You specify 'frames' here to give the number of frames in the effect
2430
+ * @param function OPTIONAL A function that will be called when the effect is complete
2431
+ */
2432
+ this.wave = function ()
2433
+ {
2434
+ var obj = this,
2435
+ opt = arguments[0] || {};
2436
+ opt.frames = opt.frames || 60;
2437
+ opt.startFrames = [];
2438
+ opt.counters = [];
2439
+
2440
+ var framesperbar = opt.frames / 3,
2441
+ frame = -1,
2442
+ callback = arguments[1] || function () {},
2443
+ original = RG.arrayClone(obj.data),
2444
+ labelsAbove = prop['chart.labels.above'];
2445
+
2446
+ this.set('labelsAbove', false);
2447
+
2448
+ for (var i=0,len=obj.data.length; i<len; i+=1) {
2449
+ opt.startFrames[i] = ((opt.frames / 2) / (obj.data.length - 1)) * i;
2450
+
2451
+ if (typeof obj.data[i] === 'object' && obj.data[i]) {
2452
+ opt.counters[i] = [];
2453
+ for (var j=0; j<obj.data[i].length; j++) {
2454
+ opt.counters[i][j] = 0;
2455
+ }
2456
+ } else {
2457
+ opt.counters[i] = 0;
2458
+ }
2459
+ }
2460
+
2461
+ /**
2462
+ * This stops the chart from jumping
2463
+ */
2464
+ obj.draw();
2465
+ obj.Set('xmax', obj.scale2.max);
2466
+ RG.clear(obj.canvas);
2467
+
2468
+ function iterator ()
2469
+ {
2470
+ ++frame;
2471
+
2472
+ for (var i=0,len=obj.data.length; i<len; i+=1) {
2473
+ if (frame > opt.startFrames[i]) {
2474
+ if (typeof obj.data[i] === 'number') {
2475
+
2476
+ obj.data[i] = ma.min(
2477
+ ma.abs(original[i]),
2478
+ ma.abs(original[i] * ( (opt.counters[i]++) / framesperbar))
2479
+ );
2480
+
2481
+ // Make the number negative if the original was
2482
+ if (original[i] < 0) {
2483
+ obj.data[i] *= -1;
2484
+ }
2485
+ } else if (!RG.isNull(obj.data[i])) {
2486
+ for (var j=0,len2=obj.data[i].length; j<len2; j+=1) {
2487
+
2488
+ obj.data[i][j] = ma.min(
2489
+ ma.abs(original[i][j]),
2490
+ ma.abs(original[i][j] * ( (opt.counters[i][j]++) / framesperbar))
2491
+ );
2492
+
2493
+ // Make the number negative if the original was
2494
+ if (original[i][j] < 0) {
2495
+ obj.data[i][j] *= -1;
2496
+ }
2497
+ }
2498
+ }
2499
+ } else {
2500
+ obj.data[i] = typeof obj.data[i] === 'object' && obj.data[i] ? RG.arrayPad([], obj.data[i].length, 0) : (RG.isNull(obj.data[i]) ? null : 0);
2501
+ }
2502
+ }
2503
+
2504
+
2505
+ if (frame >= opt.frames) {
2506
+
2507
+ if (labelsAbove) {
2508
+ obj.set('labelsAbove', true);
2509
+ RG.redrawCanvas(obj.canvas);
2510
+ }
2511
+
2512
+ callback(obj);
2513
+ } else {
2514
+ RG.redrawCanvas(obj.canvas);
2515
+ RG.Effects.updateCanvas(iterator);
2516
+ }
2517
+ }
2518
+
2519
+ iterator();
2520
+
2521
+ return this;
2522
+ };
2523
+
2524
+
2525
+
2526
+
2527
+ //
2528
+ // Determines whether the given shape is adjustable or not
2529
+ //
2530
+ // @param object The shape that pertains to the relevant bar
2531
+ //
2532
+ this.isAdjustable = function (shape)
2533
+ {
2534
+ if (RG.isNull(prop['chart.adjustable.only'])) {
2535
+ return true;
2536
+ }
2537
+
2538
+ if (RG.isArray(prop['chart.adjustable.only']) && prop['chart.adjustable.only'][shape.index]) {
2539
+ return true;
2540
+ }
2541
+
2542
+ return false;
2543
+ };
2544
+
2545
+
2546
+
2547
+
2548
+ /**
2549
+ * Charts are now always registered
2550
+ */
2551
+ RG.Register(this);
2552
+
2553
+
2554
+
2555
+
2556
+ /**
2557
+ * This is the 'end' of the constructor so if the first argument
2558
+ * contains configuration data - handle that.
2559
+ */
2560
+ if (parseConfObjectForOptions) {
2561
+ RG.parseObjectStyleConfig(this, conf.options);
2562
+ }
2563
+ };