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,116 +1,2006 @@
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.Bipolar=function(conf)
3
- {if(typeof conf==='object'&&typeof conf.left==='object'&&typeof conf.right==='object'&&typeof conf.id==='string'){var id=conf.id,canvas=document.getElementById(id),left=conf.left,right=conf.right,parseConfObjectForOptions=true}else{var id=conf,canvas=document.getElementById(id),left=arguments[1],right=arguments[2]}
4
- this.id=id;this.canvas=canvas;this.context=this.canvas.getContext('2d');this.canvas.__object__=this;this.type='bipolar';this.coords=[];this.coordsLeft=[];this.coordsRight=[];this.max=0;this.isRGraph=true;this.uid=RGraph.CreateUID();this.canvas.uid=this.canvas.uid?this.canvas.uid:RGraph.CreateUID();this.coordsText=[];this.original_colors=[];this.firstDraw=true;for(var i=0;i<left.length;++i)left[i]=parseFloat(left[i]);for(var i=0;i<right.length;++i)right[i]=parseFloat(right[i]);this.left=left;this.right=right;this.data=[left,right];this.properties={'chart.background.grid':true,'chart.background.grid.color':'#ddd','chart.background.grid.vlines':true,'chart.background.grid.hlines':true,'chart.background.grid.linewidth':1,'chart.background.grid.autofit.numvlines':null,'chart.background.grid.autofit.numhlines':null,'chart.margin':2,'chart.xtickinterval':null,'chart.labels':[],'chart.labels.color':null,'chart.labels.above':false,'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.title.left':'','chart.title.right':'','chart.gutter.center':60,'chart.gutter.left':25,'chart.gutter.right':25,'chart.gutter.top':25,'chart.gutter.bottom':30,'chart.title':'','chart.title.background':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.colors':['#0f0'],'chart.colors.sequential':false,'chart.contextmenu':null,'chart.tooltips':null,'chart.tooltips.effect':'fade','chart.tooltips.css.class':'RGraph_tooltip','chart.tooltips.highlight':true,'chart.tooltips.event':'onclick','chart.highlight.stroke':'rgba(0,0,0,0)','chart.highlight.fill':'rgba(255,255,255,0.7)','chart.units.pre':'','chart.units.post':'','chart.shadow':false,'chart.shadow.color':'#666','chart.shadow.offsetx':3,'chart.shadow.offsety':3,'chart.shadow.blur':3,'chart.annotatable':false,'chart.annotate.color':'black','chart.xmax':null,'chart.xmin':0,'chart.scale.zerostart':true,'chart.scale.decimals':null,'chart.scale.point':'.','chart.scale.thousand':',','chart.axis.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.background':null,'chart.strokestyle':'rgba(0,0,0,0)','chart.events.mousemove':null,'chart.events.click':null,'chart.linewidth':1,'chart.noaxes':false,'chart.xlabels':true,'chart.numyticks':null,'chart.numxticks':5,'chart.axis.linewidth':1,'chart.labels.count':5,'chart.variant.threed.offsetx':10,'chart.variant.threed.offsety':5,'chart.variant.threed.angle':0.1,'chart.clearto':'rgba(0,0,0,0)'}
5
- while(this.left.length<this.right.length)this.left.push(null);while(this.left.length>this.right.length)this.right.push(null);this.properties['chart.numyticks']=this.left.length;var linear_data=RGraph.arrayLinearize(this.left,this.right);for(var i=0;i<linear_data.length;++i){this['$'+i]={};}
6
- if(!this.canvas.__rgraph_aa_translated__){this.context.translate(0.5,0.5);this.canvas.__rgraph_aa_translated__=true;}
7
- var RG=RGraph,ca=this.canvas,co=ca.getContext('2d'),prop=this.properties,pa2=RG.path2,win=window,doc=document,ma=Math
8
- if(RG.Effects&&typeof RG.Effects.decorate==='function'){RG.Effects.decorate(this);}
9
- this.set=this.Set=function(name)
10
- {var value=typeof arguments[1]==='undefined'?null:arguments[1];if(arguments.length===1&&typeof name==='object'){RG.parseObjectStyleConfig(this,name);return this;}
11
- if(name.substr(0,6)!='chart.'){name='chart.'+name;}
12
- while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
13
- prop[name]=value;return this;};this.get=this.Get=function(name)
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
- return this.properties[name.toLowerCase()];};this.draw=this.Draw=function()
17
- {RG.FireCustomEvent(this,'onbeforedraw');if(!this.colorsParsed){this.parseColors();this.colorsParsed=true;}
18
- 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.gutterCenter=prop['chart.gutter.center'];this.left=this.data[0];this.right=this.data[1];this.coords=[];this.coordsText=[];if(prop['chart.variant']==='3d'){if(prop['chart.text.accessible']){}else{co.setTransform(1,prop['chart.variant.threed.angle'],0,1,0.5,0.5);}}
19
- this.axisWidth=(ca.width-prop['chart.gutter.center']-this.gutterLeft-this.gutterRight)/2;this.axisHeight=ca.height-this.gutterTop-this.gutterBottom;this.sequentialFullIndex=0;this.getMax();this.drawBackgroundGrid();this.draw3DAxes();this.drawAxes();this.drawTicks();co.save();co.beginPath();co.rect(this.gutterLeft,this.gutterTop-(prop['chart.variant.threed.offsety']||0),ca.width-this.gutterLeft-this.gutterRight,ca.height-this.gutterTop-this.gutterBottom+(2*(prop['chart.variant.threed.offsety']||0)));co.clip();this.drawLeftBars();this.drawRightBars();this.drawLeftBars({shadow:false});this.drawRightBars({shadow:false});co.restore();this.drawAxes();this.drawLabels();this.drawTitles();if(prop['chart.contextmenu']){RG.ShowContext(this);}
20
- if(prop['chart.resizable']){RG.AllowResizing(this);}
21
- RG.InstallEventListeners(this);if(this.firstDraw){RG.fireCustomEvent(this,'onfirstdraw');this.firstDraw=false;this.firstDrawFunc();}
22
- RG.FireCustomEvent(this,'ondraw');return this;};this.exec=function(func)
23
- {func(this);return this;};this.draw3DAxes=function()
24
- {if(prop['chart.variant']==='3d'){var offsetx=prop['chart.variant.threed.offsetx'],offsety=prop['chart.variant.threed.offsety'];co.lineWidth=prop['chart.axis.linewidth']+0.001;co.beginPath();co.strokeStyle=prop['chart.axis.color'];pa2(co,'b m % % l % % l % % l % % s #aaa f #ddd',this.gutterLeft,ma.round(ca.height-this.gutterBottom),this.gutterLeft+offsetx,ma.round(ca.height-this.gutterBottom-offsety),this.gutterLeft+offsetx+this.axisWidth,ma.round(ca.height-this.gutterBottom-offsety),this.gutterLeft+this.axisWidth,ma.round(ca.height-this.gutterBottom));this.draw3DLeftVerticalAxis();pa2(co,'b m % % l % % l % % l % % s #aaa f #ddd',this.gutterLeft+this.gutterCenter+this.axisWidth,ma.round(ca.height-this.gutterBottom),this.gutterLeft+this.gutterCenter+this.axisWidth+offsetx,ma.round(ca.height-this.gutterBottom-offsety),this.gutterLeft+this.gutterCenter+this.axisWidth+this.axisWidth+offsetx,ma.round(ca.height-this.gutterBottom-offsety),this.gutterLeft+this.gutterCenter+this.axisWidth+this.axisWidth,ma.round(ca.height-this.gutterBottom));pa2(co,'b m % % l % % l % % l % % s #aaa f #ddd',this.gutterLeft+this.gutterCenter+this.axisWidth,ca.height-this.gutterBottom,this.gutterLeft+this.gutterCenter+this.axisWidth,ca.height-this.gutterBottom-this.axisHeight,this.gutterLeft+this.gutterCenter+this.axisWidth+offsetx,ca.height-this.gutterBottom-this.axisHeight-offsety,this.gutterLeft+this.gutterCenter+this.axisWidth+offsetx,ca.height-this.gutterBottom-offsety);}}
25
- this.draw3DLeftVerticalAxis=function()
26
- {if(prop['chart.variant']==='3d'){var offsetx=prop['chart.variant.threed.offsetx'],offsety=prop['chart.variant.threed.offsety'];pa2(co,'b m % % l % % l % % l % % s #aaa f #ddd',this.gutterLeft+this.axisWidth,this.gutterTop,this.gutterLeft+this.axisWidth+offsetx,this.gutterTop-offsety,this.gutterLeft+this.axisWidth+offsetx,ca.height-this.gutterBottom-offsety,this.gutterLeft+this.axisWidth,ca.height-this.gutterBottom);}};this.drawAxes=this.DrawAxes=function()
27
- {co.lineWidth=prop['chart.axis.linewidth']+0.001;co.beginPath();co.strokeStyle=prop['chart.axis.color'];this.axisWidth=(ca.width-prop['chart.gutter.center']-this.gutterLeft-this.gutterRight)/2;this.axisHeight=ca.height-this.gutterTop-this.gutterBottom;if(prop['chart.noaxes']){return;}
28
- co.moveTo(this.gutterLeft,Math.round(ca.height-this.gutterBottom));co.lineTo(this.gutterLeft+this.axisWidth,Math.round(ca.height-this.gutterBottom));co.moveTo(ma.round(this.gutterLeft+this.axisWidth),ca.height-this.gutterBottom);co.lineTo(ma.round(this.gutterLeft+this.axisWidth),this.gutterTop);co.stroke();co.beginPath();var x=this.gutterLeft+this.axisWidth+prop['chart.gutter.center'];co.moveTo(Math.round(x),this.gutterTop);co.lineTo(Math.round(x),ca.height-this.gutterBottom);co.moveTo(Math.round(x),Math.round(ca.height-this.gutterBottom));co.lineTo(ca.width-this.gutterRight,Math.round(ca.height-this.gutterBottom));co.stroke();};this.drawTicks=this.DrawTicks=function()
29
- {co.lineWidth=prop['chart.axis.linewidth']+0.001;var numDataPoints=this.left.length;var barHeight=((ca.height-this.gutterTop-this.gutterBottom)-(this.left.length*(prop['chart.margin']*2)))/numDataPoints;this.barHeight=barHeight;if(prop['chart.noaxes']){return;}
30
- if(prop['chart.numyticks']>0){co.beginPath();for(var i=0;i<prop['chart.numyticks'];++i){var y=prop['chart.gutter.top']+(((ca.height-this.gutterTop-this.gutterBottom)/prop['chart.numyticks'])*i);co.moveTo(this.gutterLeft+this.axisWidth,y);co.lineTo(this.gutterLeft+this.axisWidth+3,y);}
31
- co.stroke();co.beginPath();for(var i=0;i<prop['chart.numyticks'];++i){var y=prop['chart.gutter.top']+(((ca.height-this.gutterTop-this.gutterBottom)/prop['chart.numyticks'])*i);co.moveTo(this.gutterLeft+this.axisWidth+prop['chart.gutter.center'],y);co.lineTo(this.gutterLeft+this.axisWidth+prop['chart.gutter.center']-3,y);}
32
- co.stroke();}
33
- if(prop['chart.numxticks']>0){var xInterval=this.axisWidth/prop['chart.numxticks'];if(typeof(prop['chart.xtickinterval'])=='number'){xInterval=prop['chart.xtickinterval'];}
34
- for(i=this.gutterLeft;i<(this.gutterLeft+this.axisWidth);i+=xInterval){co.beginPath();co.moveTo(Math.round(i),ca.height-this.gutterBottom);co.lineTo(Math.round(i),(ca.height-this.gutterBottom)+4);co.closePath();co.stroke();}
35
- var stoppingPoint=ca.width-this.gutterRight;for(i=(this.gutterLeft+this.axisWidth+prop['chart.gutter.center']+xInterval);i<=stoppingPoint;i+=xInterval){co.beginPath();co.moveTo(Math.round(i),ca.height-this.gutterBottom);co.lineTo(Math.round(i),(ca.height-this.gutterBottom)+4);co.closePath();co.stroke();}}};this.getMax=this.GetMax=function()
36
- {var dec=prop['chart.scale.decimals'];if(prop['chart.xmax']){var max=prop['chart.xmax'];var min=prop['chart.xmin'];this.scale2=RG.getScale2(this,{'max':max,'min':min,'strict':true,'scale.thousand':prop['chart.scale.thousand'],'scale.point':prop['chart.scale.point'],'scale.decimals':prop['chart.scale.decimals'],'ylabels.count':prop['chart.labels.count'],'scale.round':prop['chart.scale.round'],'units.pre':prop['chart.units.pre'],'units.post':prop['chart.units.post']});this.max=this.scale2.max;this.min=this.scale2.min;}else{var max=Math.max(RG.array_max(this.left),RG.array_max(this.right));this.scale2=RG.getScale2(this,{'max':max,'min':prop['chart.xmin'],'scale.thousand':prop['chart.scale.thousand'],'scale.point':prop['chart.scale.point'],'scale.decimals':prop['chart.scale.decimals'],'ylabels.count':prop['chart.labels.count'],'scale.round':prop['chart.scale.round'],'units.pre':prop['chart.units.pre'],'units.post':prop['chart.units.post']});this.max=this.scale2.max;this.min=this.scale2.min;}};this.drawLeftBars=this.DrawLeftBars=function()
37
- {var opt={};if(typeof arguments[0]==='object'){opt.shadow=arguments[0].shadow;}else{opt.shadow=true;}
38
- var offsetx=prop['chart.variant.threed.offsetx'],offsety=prop['chart.variant.threed.offsety'];co.strokeStyle=prop['chart.strokestyle'];co.lineWidth=prop['chart.linewidth'];for(var i=(this.left.length-1);i>=0;i-=1){if(prop['chart.shadow']&&prop['chart.variant']!=='3d'&&opt.shadow){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];}
39
- if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][i];}else{co.fillStyle=prop['chart.colors'][0];}
40
- var width=(((this.left[i]-this.min)/(this.max-this.min))*this.axisWidth);var coords=[ma.round(this.gutterLeft+this.axisWidth-width),ma.round(this.gutterTop+(i*(this.axisHeight/this.left.length))+prop['chart.margin']),width,this.barHeight];if(RG.ISOLD&&prop['chart.shadow']){this.drawIEShadow(coords);}
41
- if(this.left[i]!==null){co.strokeRect(coords[0],coords[1],coords[2],coords[3]);co.fillRect(coords[0],coords[1],coords[2],coords[3]);}
42
- if(prop['chart.variant']==='3d'&&this.left[i]!==null){if(prop['chart.shadow']&&opt.shadow){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];pa2(co,'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety+coords[3],coords[0]+offsetx,coords[1]-offsety+coords[3]);}
43
- if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][i];}else{co.fillStyle=prop['chart.colors'][0];}
44
- pa2(co,'b m % % l % % l % % l % % f %',coords[0],coords[1],coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+coords[2],coords[1]);pa2(co,'b m % % l % % l % % l % % f rgba(255,255,255,0.4)',coords[0],coords[1],coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+coords[2],coords[1]);}
45
- this.draw3DLeftVerticalAxis();this.coords.push([coords[0],coords[1],coords[2],coords[3]]);this.coordsLeft.push([coords[0],coords[1],coords[2],coords[3]]);}
46
- RG.noShadow(this);co.lineWidth=1;};this.drawRightBars=this.DrawRightBars=function()
47
- {var opt={};if(typeof arguments[0]==='object'){opt.shadow=arguments[0].shadow;}else{opt.shadow=true;}
48
- var offsetx=prop['chart.variant.threed.offsetx'],offsety=prop['chart.variant.threed.offsety'];co.strokeStyle=prop['chart.strokestyle'];co.lineWidth=prop['chart.linewidth'];if(prop['chart.shadow']&&prop['chart.variant']!=='3d'&&opt.shadow){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];}
49
- for(var i=(this.right.length-1);i>=0;i-=1){if(prop['chart.colors.sequential']){co.fillStyle=prop['chart.colors'][i];}else{co.fillStyle=prop['chart.colors'][0];}
50
- var width=(((this.right[i]-this.min)/(this.max-this.min))*this.axisWidth);var coords=[ma.round(this.gutterLeft+this.axisWidth+prop['chart.gutter.center']),ma.round(prop['chart.margin']+(i*(this.axisHeight/this.right.length))+this.gutterTop),width,this.barHeight];if(RG.ISOLD&&prop['chart.shadow']){this.DrawIEShadow(coords);}
51
- if(this.right[i]!==null){co.strokeRect(ma.round(coords[0]),Math.round(coords[1]),coords[2],coords[3]);co.fillRect(ma.round(coords[0]),Math.round(coords[1]),coords[2],coords[3]);}
52
- if(prop['chart.variant']==='3d'&&this.right[i]!==null){var color=co.fillStyle;if(prop['chart.shadow']&&opt.shadow){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];pa2(co,'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety+coords[3],coords[0]+offsetx,coords[1]-offsety+coords[3]);}
53
- pa2(co,'b m % % l % % l % % l % % f %',coords[0],coords[1],coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+coords[2],coords[1],color);pa2(co,'b m % % l % % l % % l % % f %',coords[0]+coords[2],coords[1],coords[0]+coords[2]+offsetx,coords[1]-offsety,coords[0]+coords[2]+offsetx,coords[1]-offsety+coords[3],coords[0]+coords[2],coords[1]+coords[3],color);pa2(co,'b m % % l % % l % % l % % f rgba(255,255,255,0.6)',coords[0],coords[1],coords[0]+offsetx,coords[1]-offsety,coords[0]+offsetx+coords[2],coords[1]-offsety,coords[0]+coords[2],coords[1]);pa2(co,'b m % % l % % l % % l % % f rgba(0,0,0,0.3)',coords[0]+coords[2],coords[1],coords[0]+coords[2]+offsetx,coords[1]-offsety,coords[0]+coords[2]+offsetx,coords[1]-offsety+coords[3],coords[0]+coords[2],coords[1]+coords[3]);}
54
- this.coords.push([coords[0],coords[1],coords[2],coords[3]]);this.coordsRight.push([coords[0],coords[1],coords[2],coords[3]]);}
55
- RG.NoShadow(this);co.lineWidth=1;};this.drawLabels=this.DrawLabels=function()
56
- {var font=prop['chart.text.font'],color=prop['chart.labels.color']||prop['chart.text.color'],size=prop['chart.text.size'],labels=prop['chart.labels'],barAreaHeight=ca.height-this.gutterTop-this.gutterBottom
57
- co.fillStyle=color;for(var i=0,len=labels.length;i<len;i+=1){RG.Text2(this,{'color':color,'font':font,'size':size,'x':this.gutterLeft+this.axisWidth+(prop['chart.gutter.center']/2),'y':this.gutterTop+((barAreaHeight/labels.length)*(i))+((barAreaHeight/labels.length)/2),'text':String(labels[i]?String(labels[i]):''),'halign':'center','valign':'center','marker':false,'tag':'labels'});}
58
- co.fillStyle=prop['chart.text.color'];if(prop['chart.xlabels']){var grapharea=(ca.width-prop['chart.gutter.center']-this.gutterLeft-this.gutterRight)/2;for(var i=0;i<this.scale2.labels.length;++i){RG.text2(this,{'font':font,'size':size,'x':this.gutterLeft+((grapharea/this.scale2.labels.length)*i),'y':ca.height-this.gutterBottom+3,'text':this.scale2.labels[this.scale2.labels.length-i-1],'valign':'top','halign':'center','tag':'scale'});RG.text2(this,{'font':font,'size':size,'x':this.gutterLeft+grapharea+prop['chart.gutter.center']+((grapharea/this.scale2.labels.length)*(i+1)),'y':ca.height-this.gutterBottom+3,'text':this.scale2.labels[i],'valign':'top','halign':'center','tag':'scale'});}
59
- if(prop['chart.scale.zerostart']){RG.text2(this,{'font':font,'size':size,'x':this.gutterLeft+this.axisWidth,'y':ca.height-this.gutterBottom+3,'text':'0','valign':'top','halign':'center','tag':'scale'});RG.text2(this,{'font':font,'size':size,'x':this.gutterLeft+this.axisWidth+this.gutterCenter,'y':ca.height-this.gutterBottom+3,'text':'0','valign':'top','halign':'center','tag':'scale'});}}
60
- if(prop['chart.labels.above']){var coordsLeft=RG.arrayReverse(this.coordsLeft);for(var i=0;i<coordsLeft.length;++i){if(typeof this.left[i]!=='number'){continue;}
61
- var coords=coordsLeft[i];RG.text2(this,{font:font,size:size,x:coords[0]-5,y:coords[1]+(coords[3]/2),text:RG.numberFormat(this,this.left[i],prop['chart.units.pre'],prop['chart.units.post']),valign:'center',halign:'right',tag:'labels.above'});}
62
- var coordsRight=RG.arrayReverse(this.coordsRight);for(i=0;i<coordsRight.length;++i){if(typeof this.right[i]!='number'){continue;}
63
- var coords=coordsRight[i];RG.Text2(this,{'font':font,'size':size,'x':coords[0]+coords[2]+5,'y':coords[1]+(coords[3]/2),'text':RG.number_format(this,this.right[i],prop['chart.units.pre'],prop['chart.units.post']),'valign':'center','halign':'left','tag':'labels.above'});}}};this.drawTitles=this.DrawTitles=function()
64
- {RG.Text2(this,{'font':prop['chart.text.font'],'size':prop['chart.text.size'],'x':this.gutterLeft+5,'y':this.gutterTop-5,'text':String(prop['chart.title.left']),'halign':'left','valign':'bottom','tag':'title.left'});RG.Text2(this,{'font':prop['chart.text.font'],'size':prop['chart.text.size'],'x':ca.width-this.gutterRight-5,'y':this.gutterTop-5,'text':String(prop['chart.title.right']),'halign':'right','valign':'bottom','tag':'title.right'});RG.drawTitle(this,prop['chart.title'],this.gutterTop,null,prop['chart.title.size']?prop['chart.title.size']:null);};this.drawIEShadow=this.DrawIEShadow=function(coords)
65
- {var prevFillStyle=co.fillStyle;var offsetx=prop['chart.shadow.offsetx'];var offsety=prop['chart.shadow.offsety'];co.lineWidth=prop['chart.linewidth'];co.fillStyle=prop['chart.shadow.color'];co.beginPath();co.fillRect(coords[0]+offsetx,coords[1]+offsety,coords[2],coords[3]);co.fill();co.fillStyle=prevFillStyle;}
66
- this.getShape=this.getBar=function(e)
67
- {var canvas=this.canvas,context=this.context,mouseCoords=RG.getMouseXY(e)
68
- for(var i=0;i<this.coords.length;i++){var mouseX=mouseCoords[0],mouseY=mouseCoords[1],left=this.coords[i][0],top=this.coords[i][1],width=this.coords[i][2],height=this.coords[i][3]
69
- pa2(co,'b r % % % %',left,top,width,height);if(co.isPointInPath(mouseX,mouseY)){var tooltip=RG.parseTooltipText(prop['chart.tooltips'],i);return{0:this,1:left,2:top,3:width,4:height,5:i,'object':this,'x':left,'y':top,'width':width,'height':height,'index':i,'tooltip':tooltip};}}
70
- return null;};this.highlight=this.Highlight=function(shape)
71
- {if(typeof prop['chart.highlight.style']==='function'){(prop['chart.highlight.style'])(shape);}else{RG.Highlight.Rect(this,shape);}};this.getValue=function(e)
72
- {var obj=e.target.__object__;var mouseXY=RG.getMouseXY(e);var mouseX=mouseXY[0];if(mouseX>this.gutterLeft&&mouseX<((ca.width/2)-(prop['chart.gutter.center']/2))){var value=(mouseX-prop['chart.gutter.left'])/this.axisWidth;value=this.max-(value*this.max);}
73
- if(mouseX<(ca.width-this.gutterRight)&&mouseX>((ca.width/2)+(prop['chart.gutter.center']/2))){var value=(mouseX-prop['chart.gutter.left']-this.axisWidth-prop['chart.gutter.center'])/this.axisWidth;value=(value*this.max);}
74
- return value;};this.getObjectByXY=function(e)
75
- {var mouseXY=RG.getMouseXY(e);if(prop['chart.variant']==='3d'){var adjustment=prop['chart.variant.threed.angle']*mouseXY[0];mouseXY[1]-=adjustment;}
76
- if(mouseXY[0]>prop['chart.gutter.left']&&mouseXY[0]<(ca.width-prop['chart.gutter.right'])&&mouseXY[1]>prop['chart.gutter.top']&&mouseXY[1]<(ca.height-prop['chart.gutter.bottom'])){return this;}};this.getXCoord=function(value)
77
- {if(value>this.max||value<0){return null;}
78
- var ret=[];var offset=((value/this.max)*this.axisWidth);ret[0]=(this.gutterLeft+this.axisWidth)-offset;ret[1]=(ca.width-this.gutterRight-this.axisWidth)+offset;return ret;};this.parseColors=function()
79
- {if(this.original_colors.length===0){this.original_colors['chart.colors']=RG.array_clone(prop['chart.colors']);this.original_colors['chart.highlight.stroke']=RG.array_clone(prop['chart.highlight.fill']);this.original_colors['chart.highlight.fill']=RG.array_clone(prop['chart.highlight.fill']);this.original_colors['chart.axis.color']=RG.array_clone(prop['chart.axis.color']);this.original_colors['chart.strokestyle']=RG.array_clone(prop['chart.strokestyle']);}
80
- var props=this.properties;var colors=props['chart.colors'];for(var i=0;i<colors.length;++i){colors[i]=this.parseSingleColorForGradient(colors[i]);}
81
- props['chart.highlight.stroke']=this.parseSingleColorForGradient(props['chart.highlight.stroke']);props['chart.highlight.fill']=this.parseSingleColorForGradient(props['chart.highlight.fill']);props['chart.axis.color']=this.parseSingleColorForGradient(props['chart.axis.color']);props['chart.strokestyle']=this.parseSingleColorForGradient(props['chart.strokestyle']);};this.reset=function()
82
- {};this.parseSingleColorForGradient=function(color)
83
- {if(!color||typeof(color)!='string'){return color;}
84
- if(color.match(/^gradient\((.*)\)$/i)){var parts=RegExp.$1.split(':');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]));}}
85
- return grad?grad:color;};this.on=function(type,func)
86
- {if(type.substr(0,2)!=='on'){type='on'+type;}
87
- if(typeof this[type]!=='function'){this[type]=func;}else{RG.addCustomEventListener(this,type,func);}
88
- return this;};this.drawBackgroundGrid=function()
89
- {if(prop['chart.background.grid']){var variant=prop['chart.variant'],color=prop['chart.background.grid.color'],numvlines=prop['chart.labels.count'],numhlines=this.left.length,vlines=prop['chart.background.grid.vlines'],hlines=prop['chart.background.grid.hlines'],linewidth=prop['chart.background.grid.linewidth'];if(typeof prop['chart.background.grid.autofit.numhlines']==='number'){numhlines=prop['chart.background.grid.autofit.numhlines'];}
90
- if(typeof prop['chart.background.grid.autofit.numvlines']==='number'){numvlines=prop['chart.background.grid.autofit.numvlines'];}
91
- co.lineWidth=linewidth;if(variant=='3d'){co.save();co.translate(prop['chart.variant.threed.offsetx'],-1*prop['chart.variant.threed.offsety']);}
92
- if(vlines){for(var i=0;i<=numvlines;i+=1){pa2(co,'b m % % l % % s %',this.gutterLeft+(this.axisWidth/numvlines)*i,this.gutterTop,this.gutterLeft+(this.axisWidth/numvlines)*i,this.gutterTop+this.axisHeight,color);}}
93
- if(hlines){for(var i=0;i<=numhlines;i+=1){pa2(co,'b m % % l % % s %',this.gutterLeft,this.gutterTop+(this.axisHeight/numhlines)*i,this.gutterLeft+this.axisWidth,this.gutterTop+(this.axisHeight/numhlines)*i,color);}}
94
- if(vlines){for(var i=0;i<=numvlines;i+=1){pa2(co,'b m % % l % % s %',this.gutterLeft+this.gutterCenter+this.axisWidth+(this.axisWidth/numvlines)*i,this.gutterTop,this.gutterLeft+this.gutterCenter+this.axisWidth+(this.axisWidth/numvlines)*i,this.gutterTop+this.axisHeight,color);}}
95
- if(hlines){for(var i=0;i<=numhlines;i+=1){pa2(co,'b m % % l % % s %',this.gutterLeft+this.axisWidth+this.gutterCenter,this.gutterTop+(this.axisHeight/numhlines)*i,this.gutterLeft+this.axisWidth+this.gutterCenter+this.axisWidth,this.gutterTop+(this.axisHeight/numhlines)*i,color);}}
96
- if(variant=='3d'){co.restore();}}};this.firstDrawFunc=function()
97
- {if(prop['chart.tooltips']){prop['chart.tooltips']=RG.arrayReverse(prop['chart.tooltips']);}};RG.Register(this);if(parseConfObjectForOptions){RG.parseObjectStyleConfig(this,conf.options);}
98
- this.grow=function()
99
- {var opt=arguments[0]||{};var frames=opt.frames||30;var frame=0;var callback=arguments[1]||function(){};var obj=this;var originalLeft=RG.arrayClone(this.left);var originalRight=RG.arrayClone(this.right);if(RG.isNull(prop['chart.xmax'])){var xmax=0;for(var i=0;i<this.left.length;i+=1){xmax=ma.max(xmax,ma.abs(this.left[i]));}
100
- for(var i=0;i<this.right.length;i+=1){xmax=ma.max(xmax,ma.abs(this.right[i]));}
101
- var scale=RG.getScale2(obj,{'max':xmax});this.Set('chart.xmax',scale.max);}
102
- var iterator=function()
103
- {var easingMultiplier=RG.Effects.getEasingMultiplier(frames,frame);for(var i=0;i<obj.left.length;i+=1){obj.left[i]=easingMultiplier*originalLeft[i];}
104
- for(var i=0;i<obj.right.length;i+=1){obj.right[i]=easingMultiplier*originalRight[i];}
105
- RG.redrawCanvas(obj.canvas);if(frame<frames){frame+=1;RG.Effects.updateCanvas(iterator);}else{callback(obj);}};iterator();return this;};this.wave=function()
106
- {var obj=this,opt=arguments[0]||{};opt.frames=opt.frames||60;opt.startFrames_left=[];opt.startFrames_right=[];opt.counters_left=[];opt.counters_right=[];var framesperbar=opt.frames/3,frame_left=-1,frame_right=-1,callback=arguments[1]||function(){},original_left=RG.arrayClone(obj.left),original_right=RG.arrayClone(obj.right);for(var i=0,len=obj.left.length;i<len;i+=1){opt.startFrames_left[i]=((opt.frames/2)/(obj.left.length-1))*i;opt.startFrames_right[i]=((opt.frames/2)/(obj.right.length-1))*i;opt.counters_left[i]=0;opt.counters_right[i]=0;}
107
- obj.draw();obj.set('xmax',obj.scale2.max);RG.clear(obj.canvas);for(var i=0,len=obj.left.length;i<len;i+=1){if(typeof obj.left[i]==='number')obj.left[i]=0;if(typeof obj.right[i]==='number')obj.right[i]=0;}
108
- function iteratorLeft()
109
- {++frame_left;for(var i=0,len=obj.left.length;i<len;i+=1){if(frame_left>opt.startFrames_left[i]){var isNull=RG.isNull(obj.left[i]);obj.left[i]=ma.min(ma.abs(original_left[i]),ma.abs(original_left[i]*((opt.counters_left[i]++)/framesperbar)));if(original_left[i]<0){obj.left[i]*=-1;}
110
- if(isNull){obj.left[i]=null;}}else{obj.left[i]=typeof obj.left[i]==='object'&&obj.left[i]?RG.arrayPad([],obj.left[i].length,0):(RG.isNull(obj.left[i])?null:0);}}
111
- if(frame_left<opt.frames){RG.redrawCanvas(obj.canvas);RG.Effects.updateCanvas(iteratorLeft);}}
112
- function iteratorRight()
113
- {++frame_right;for(var i=0,len=obj.right.length;i<len;i+=1){if(frame_right>opt.startFrames_right[i]){var isNull=RG.isNull(obj.right[i]);obj.right[i]=ma.min(ma.abs(original_right[i]),ma.abs(original_right[i]*((opt.counters_right[i]++)/framesperbar)));if(original_right[i]<0){obj.right[i]*=-1;}
114
- if(isNull){obj.right[i]=null;}}else{obj.right[i]=typeof obj.right[i]==='object'&&obj.right[i]?RG.arrayPad([],obj.right[i].length,0):(RG.isNull(obj.right[i])?null:0);}}
115
- if(frame_right<opt.frames){RG.redrawCanvas(obj.canvas);RG.Effects.updateCanvas(iteratorRight);}else{callback(this);}}
116
- iteratorLeft();iteratorRight();return this;};};
13
+ RGraph = window.RGraph || {isRGraph: true};
14
+
15
+ /**
16
+ * The bi-polar/age frequency constructor.
17
+ *
18
+ * @param string id The id of the canvas
19
+ * @param array left The left set of data points
20
+ * @param array right The right set of data points
21
+ *
22
+ * REMEMBER If ymin is implemented you need to update the .getValue() method
23
+ */
24
+ RGraph.Bipolar = function (conf)
25
+ {
26
+ /**
27
+ * Allow for object config style
28
+ */
29
+ if ( typeof conf === 'object'
30
+ && typeof conf.left === 'object'
31
+ && typeof conf.right === 'object'
32
+ && typeof conf.id === 'string') {
33
+
34
+ var id = conf.id,
35
+ canvas = document.getElementById(id),
36
+ left = conf.left,
37
+ right = conf.right,
38
+ parseConfObjectForOptions = true // Set this so the config is parsed (at the end of the constructor)
39
+
40
+ } else {
41
+
42
+ var id = conf,
43
+ canvas = document.getElementById(id),
44
+ left = arguments[1],
45
+ right = arguments[2]
46
+ }
47
+
48
+
49
+
50
+ // Get the canvas and context objects
51
+ this.id = id;
52
+ this.canvas = canvas;
53
+ this.context = this.canvas.getContext('2d');
54
+ this.canvas.__object__ = this;
55
+ this.type = 'bipolar';
56
+ this.coords = [];
57
+ this.coordsLeft = [];
58
+ this.coordsRight = [];
59
+ this.max = 0;
60
+ this.isRGraph = true;
61
+ this.uid = RGraph.CreateUID();
62
+ this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID();
63
+ this.coordsText = [];
64
+ this.original_colors = [];
65
+ this.firstDraw = true; // After the first draw this will be false
66
+
67
+
68
+ /**
69
+ * Compatibility with older browsers
70
+ */
71
+ //RGraph.OldBrowserCompat(this.context);
72
+
73
+
74
+ // The left and right data respectively. Ensure that the data is an array
75
+ // of numbers
76
+ for (var i=0; i<left.length; ++i) left[i] = parseFloat(left[i]);
77
+ for (var i=0; i<right.length; ++i) right[i] = parseFloat(right[i]);
78
+
79
+ this.left = left;
80
+ this.right = right;
81
+ this.data = [left, right];
82
+
83
+ this.properties =
84
+ {
85
+ 'chart.background.grid': true,
86
+ 'chart.background.grid.color': '#ddd',
87
+ 'chart.background.grid.vlines': true,
88
+ 'chart.background.grid.hlines': true,
89
+ 'chart.background.grid.linewidth': 1,
90
+ 'chart.background.grid.autofit.numvlines': null,
91
+ 'chart.background.grid.autofit.numhlines': null,
92
+ 'chart.margin': 2,
93
+ 'chart.xtickinterval': null,
94
+ 'chart.labels': [],
95
+ 'chart.labels.color': null,
96
+ 'chart.labels.above': false,
97
+ 'chart.text.size': 12,
98
+ 'chart.text.color': 'black', // (Simple) gradients are not supported
99
+ 'chart.text.font': 'Segoe UI, Arial, Verdana, sans-serif',
100
+ 'chart.text.accessible': true,
101
+ 'chart.text.accessible.overflow': 'visible',
102
+ 'chart.text.accessible.pointerevents': true,
103
+ 'chart.title.left': '',
104
+ 'chart.title.right': '',
105
+ 'chart.gutter.center': 60,
106
+ 'chart.gutter.left': 25,
107
+ 'chart.gutter.right': 25,
108
+ 'chart.gutter.top': 25,
109
+ 'chart.gutter.bottom': 30,
110
+ 'chart.title': '',
111
+ 'chart.title.background': null,
112
+ 'chart.title.hpos': null,
113
+ 'chart.title.vpos': null,
114
+ 'chart.title.bold': true,
115
+ 'chart.title.font': null,
116
+ 'chart.title.x': null,
117
+ 'chart.title.y': null,
118
+ 'chart.title.halign': null,
119
+ 'chart.title.valign': null,
120
+ 'chart.colors': ['#0f0'],
121
+ 'chart.colors.sequential': false,
122
+ 'chart.contextmenu': null,
123
+ 'chart.tooltips': null,
124
+ 'chart.tooltips.effect': 'fade',
125
+ 'chart.tooltips.css.class': 'RGraph_tooltip',
126
+ 'chart.tooltips.highlight': true,
127
+ 'chart.tooltips.event': 'onclick',
128
+ 'chart.highlight.stroke': 'rgba(0,0,0,0)',
129
+ 'chart.highlight.fill': 'rgba(255,255,255,0.7)',
130
+ 'chart.units.pre': '',
131
+ 'chart.units.post': '',
132
+ 'chart.shadow': false,
133
+ 'chart.shadow.color': '#666',
134
+ 'chart.shadow.offsetx': 3,
135
+ 'chart.shadow.offsety': 3,
136
+ 'chart.shadow.blur': 3,
137
+ 'chart.annotatable': false,
138
+ 'chart.annotate.color': 'black',
139
+ 'chart.xmax': null,
140
+ 'chart.xmin': 0,
141
+ 'chart.scale.zerostart': true,
142
+ 'chart.scale.decimals': null,
143
+ 'chart.scale.point': '.',
144
+ 'chart.scale.thousand': ',',
145
+ 'chart.axis.color': 'black',
146
+ 'chart.zoom.factor': 1.5,
147
+ 'chart.zoom.fade.in': true,
148
+ 'chart.zoom.fade.out': true,
149
+ 'chart.zoom.hdir': 'right',
150
+ 'chart.zoom.vdir': 'down',
151
+ 'chart.zoom.frames': 25,
152
+ 'chart.zoom.delay': 16.666,
153
+ 'chart.zoom.shadow': true,
154
+ 'chart.zoom.background': true,
155
+ 'chart.zoom.action': 'zoom',
156
+ 'chart.resizable': false,
157
+ 'chart.resize.handle.background': null,
158
+ 'chart.strokestyle': 'rgba(0,0,0,0)',
159
+ 'chart.events.mousemove': null,
160
+ 'chart.events.click': null,
161
+ 'chart.linewidth': 1,
162
+ 'chart.noaxes': false,
163
+ 'chart.xlabels': true,
164
+ 'chart.numyticks': null,
165
+ 'chart.numxticks': 5,
166
+ 'chart.axis.linewidth': 1,
167
+ 'chart.labels.count': 5,
168
+ 'chart.variant.threed.offsetx': 10,
169
+ 'chart.variant.threed.offsety': 5,
170
+ 'chart.variant.threed.angle': 0.1,
171
+ 'chart.clearto': 'rgba(0,0,0,0)'
172
+ }
173
+
174
+ // Pad the arrays so they're the same size
175
+ while (this.left.length < this.right.length) this.left.push(null);
176
+ while (this.left.length > this.right.length) this.right.push(null);
177
+
178
+ /**
179
+ * Set the default for the number of Y tickmarks
180
+ */
181
+ this.properties['chart.numyticks'] = this.left.length;
182
+
183
+
184
+
185
+
186
+ /**
187
+ * Create the dollar objects so that functions can be added to them
188
+ */
189
+ var linear_data = RGraph.arrayLinearize(this.left, this.right);
190
+
191
+ for (var i=0; i<linear_data.length; ++i) {
192
+ this['$' + i] = {};
193
+ }
194
+
195
+
196
+ /**
197
+ * Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
198
+ * done already
199
+ */
200
+ if (!this.canvas.__rgraph_aa_translated__) {
201
+ this.context.translate(0.5,0.5);
202
+
203
+ this.canvas.__rgraph_aa_translated__ = true;
204
+ }
205
+
206
+
207
+
208
+
209
+ // Short variable names
210
+ var RG = RGraph,
211
+ ca = this.canvas,
212
+ co = ca.getContext('2d'),
213
+ prop = this.properties,
214
+ pa2 = RG.path2,
215
+ win = window,
216
+ doc = document,
217
+ ma = Math
218
+
219
+
220
+
221
+ /**
222
+ * "Decorate" the object with the generic effects if the effects library has been included
223
+ */
224
+ if (RG.Effects && typeof RG.Effects.decorate === 'function') {
225
+ RG.Effects.decorate(this);
226
+ }
227
+
228
+
229
+
230
+
231
+
232
+
233
+
234
+ /**
235
+ * The setter
236
+ *
237
+ * @param name string The name of the parameter to set
238
+ * @param value mixed The value of the paraneter
239
+ */
240
+ this.set =
241
+ this.Set = function (name)
242
+ {
243
+ var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
244
+
245
+
246
+ /**
247
+ * the number of arguments is only one and it's an
248
+ * object - parse it for configuration data and return.
249
+ */
250
+ if (arguments.length === 1 && typeof name === 'object') {
251
+ RG.parseObjectStyleConfig(this, name);
252
+ return this;
253
+ }
254
+
255
+
256
+
257
+
258
+
259
+ /**
260
+ * This should be done first - prepend the propertyy name with "chart." if necessary
261
+ */
262
+ if (name.substr(0,6) != 'chart.') {
263
+ name = 'chart.' + name;
264
+ }
265
+
266
+
267
+
268
+
269
+ // Convert uppercase letters to dot+lower case letter
270
+ while(name.match(/([A-Z])/)) {
271
+ name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
272
+ }
273
+
274
+
275
+
276
+
277
+
278
+
279
+ prop[name] = value;
280
+
281
+ return this;
282
+ };
283
+
284
+
285
+
286
+
287
+ /**
288
+ * The getter
289
+ *
290
+ * @param name string The name of the parameter to get
291
+ */
292
+ this.get =
293
+ this.Get = function (name)
294
+ {
295
+ /**
296
+ * This should be done first - prepend the property name with "chart." if necessary
297
+ */
298
+ if (name.substr(0,6) != 'chart.') {
299
+ name = 'chart.' + name;
300
+ }
301
+
302
+ // Convert uppercase letters to dot+lower case letter
303
+ while(name.match(/([A-Z])/)) {
304
+ name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
305
+ }
306
+
307
+ return this.properties[name.toLowerCase()];
308
+ };
309
+
310
+
311
+
312
+
313
+ /**
314
+ * Draws the graph
315
+ */
316
+ this.draw =
317
+ this.Draw = function ()
318
+ {
319
+ /**
320
+ * Fire the onbeforedraw event
321
+ */
322
+ RG.FireCustomEvent(this, 'onbeforedraw');
323
+
324
+
325
+ /**
326
+ * Parse the colors. This allows for simple gradient syntax
327
+ */
328
+ if (!this.colorsParsed) {
329
+ this.parseColors();
330
+
331
+ // Don't want to do this again
332
+ this.colorsParsed = true;
333
+ }
334
+
335
+
336
+ /**
337
+ * This is new in May 2011 and facilitates indiviual gutter settings,
338
+ * eg chart.gutter.left
339
+ */
340
+ this.gutterLeft = prop['chart.gutter.left'];
341
+ this.gutterRight = prop['chart.gutter.right'];
342
+ this.gutterTop = prop['chart.gutter.top'];
343
+ this.gutterBottom = prop['chart.gutter.bottom'];
344
+ this.gutterCenter = prop['chart.gutter.center'];
345
+
346
+
347
+
348
+ // Reset the data to what was initially supplied
349
+ this.left = this.data[0];
350
+ this.right = this.data[1];
351
+
352
+
353
+ /**
354
+ * Reset the coords array
355
+ */
356
+ this.coords = [];
357
+
358
+
359
+
360
+ /**
361
+ * Stop this growing uncontrollably
362
+ */
363
+ this.coordsText = [];
364
+
365
+
366
+ if (prop['chart.variant'] === '3d') {
367
+ if (prop['chart.text.accessible']) {
368
+ // Nada
369
+ } else {
370
+ co.setTransform(1,prop['chart.variant.threed.angle'],0,1,0.5,0.5);
371
+ }
372
+ }
373
+
374
+
375
+
376
+ // Some necessary variables
377
+ this.axisWidth = (ca.width - prop['chart.gutter.center'] - this.gutterLeft - this.gutterRight) / 2;
378
+ this.axisHeight = ca.height - this.gutterTop - this.gutterBottom;
379
+
380
+
381
+ // Reset the sequential index
382
+ this.sequentialFullIndex = 0;
383
+
384
+
385
+
386
+ this.getMax();
387
+ this.drawBackgroundGrid();
388
+ this.draw3DAxes();
389
+ this.drawAxes();
390
+ this.drawTicks();
391
+
392
+ co.save();
393
+ co.beginPath();
394
+ co.rect(this.gutterLeft, this.gutterTop - (prop['chart.variant.threed.offsety'] || 0), ca.width - this.gutterLeft - this.gutterRight, ca.height - this.gutterTop - this.gutterBottom + (2 * (prop['chart.variant.threed.offsety'] || 0)) );
395
+ co.clip();
396
+
397
+ this.drawLeftBars();
398
+ this.drawRightBars();
399
+
400
+ // Redraw the bars so that shadows on not on top
401
+ this.drawLeftBars({shadow: false});
402
+ this.drawRightBars({shadow: false});
403
+ co.restore();
404
+
405
+ this.drawAxes();
406
+
407
+ this.drawLabels();
408
+ this.drawTitles();
409
+
410
+
411
+ /**
412
+ * Setup the context menu if required
413
+ */
414
+ if (prop['chart.contextmenu']) {
415
+ RG.ShowContext(this);
416
+ }
417
+
418
+
419
+ /**
420
+ * This function enables resizing
421
+ */
422
+ if (prop['chart.resizable']) {
423
+ RG.AllowResizing(this);
424
+ }
425
+
426
+
427
+ /**
428
+ * This installs the event listeners
429
+ */
430
+ RG.InstallEventListeners(this);
431
+
432
+
433
+ /**
434
+ * Fire the onfirstdraw event
435
+ */
436
+ if (this.firstDraw) {
437
+ RG.fireCustomEvent(this, 'onfirstdraw');
438
+ this.firstDraw = false;
439
+ this.firstDrawFunc();
440
+ }
441
+
442
+
443
+ /**
444
+ * Fire the RGraph ondraw event
445
+ */
446
+ RG.FireCustomEvent(this, 'ondraw');
447
+
448
+ return this;
449
+ };
450
+
451
+
452
+
453
+ /**
454
+ * Used in chaining. Runs a function there and then - not waiting for
455
+ * the events to fire (eg the onbeforedraw event)
456
+ *
457
+ * @param function func The function to execute
458
+ */
459
+ this.exec = function (func)
460
+ {
461
+ func(this);
462
+
463
+ return this;
464
+ };
465
+
466
+
467
+
468
+
469
+ /**
470
+ * Draws the axes
471
+ */
472
+ this.draw3DAxes = function ()
473
+ {
474
+ if (prop['chart.variant'] === '3d') {
475
+ var offsetx = prop['chart.variant.threed.offsetx'],
476
+ offsety = prop['chart.variant.threed.offsety'];
477
+
478
+ // Set the linewidth
479
+ co.lineWidth = prop['chart.axis.linewidth'] + 0.001;
480
+
481
+
482
+ // Draw the left set of axes
483
+ co.beginPath();
484
+ co.strokeStyle = prop['chart.axis.color'];
485
+
486
+ // Draw the horizontal 3d axis
487
+ // The left horizontal axis
488
+ pa2(co,
489
+ 'b m % % l % % l % % l % % s #aaa f #ddd',
490
+ this.gutterLeft, ma.round( ca.height - this.gutterBottom),
491
+ this.gutterLeft + offsetx, ma.round( ca.height - this.gutterBottom - offsety),
492
+ this.gutterLeft + offsetx + this.axisWidth, ma.round( ca.height - this.gutterBottom - offsety),
493
+ this.gutterLeft + this.axisWidth, ma.round( ca.height - this.gutterBottom)
494
+ );
495
+
496
+ // The left vertical axis
497
+ this.draw3DLeftVerticalAxis();
498
+
499
+
500
+
501
+
502
+ // Draw the right horizontal axes
503
+ pa2(co,
504
+ 'b m % % l % % l % % l % % s #aaa f #ddd',
505
+ this.gutterLeft + this.gutterCenter + this.axisWidth, ma.round( ca.height - this.gutterBottom),
506
+ this.gutterLeft + this.gutterCenter + this.axisWidth + offsetx, ma.round( ca.height - this.gutterBottom - offsety),
507
+ this.gutterLeft + this.gutterCenter + this.axisWidth + this.axisWidth + offsetx, ma.round( ca.height - this.gutterBottom - offsety),
508
+ this.gutterLeft + this.gutterCenter + this.axisWidth + this.axisWidth, ma.round( ca.height - this.gutterBottom)
509
+ );
510
+
511
+
512
+
513
+
514
+ // Draw the right vertical axes
515
+ pa2(co,
516
+ 'b m % % l % % l % % l % % s #aaa f #ddd',
517
+ this.gutterLeft + this.gutterCenter + this.axisWidth, ca.height - this.gutterBottom,
518
+ this.gutterLeft + this.gutterCenter + this.axisWidth, ca.height - this.gutterBottom - this.axisHeight,
519
+ this.gutterLeft + this.gutterCenter + this.axisWidth + offsetx, ca.height - this.gutterBottom - this.axisHeight - offsety,
520
+ this.gutterLeft + this.gutterCenter + this.axisWidth + offsetx, ca.height - this.gutterBottom - offsety
521
+ );
522
+ }
523
+ }
524
+
525
+
526
+
527
+
528
+ this.draw3DLeftVerticalAxis = function ()
529
+ {
530
+ if (prop['chart.variant'] === '3d') {
531
+ var offsetx = prop['chart.variant.threed.offsetx'],
532
+ offsety = prop['chart.variant.threed.offsety'];
533
+
534
+ // The left vertical axis
535
+ pa2(co,
536
+ 'b m % % l % % l % % l % % s #aaa f #ddd',
537
+ this.gutterLeft + this.axisWidth, this.gutterTop,
538
+ this.gutterLeft + this.axisWidth + offsetx, this.gutterTop - offsety,
539
+ this.gutterLeft + this.axisWidth + offsetx, ca.height - this.gutterBottom - offsety,
540
+ this.gutterLeft + this.axisWidth, ca.height - this.gutterBottom
541
+ );
542
+ }
543
+ };
544
+
545
+
546
+
547
+
548
+ /**
549
+ * Draws the axes
550
+ */
551
+ this.drawAxes =
552
+ this.DrawAxes = function ()
553
+ {
554
+ // Set the linewidth
555
+ co.lineWidth = prop['chart.axis.linewidth'] + 0.001;
556
+
557
+
558
+ // Draw the left set of axes
559
+ co.beginPath();
560
+ co.strokeStyle = prop['chart.axis.color'];
561
+
562
+ this.axisWidth = (ca.width - prop['chart.gutter.center'] - this.gutterLeft - this.gutterRight) / 2;
563
+ this.axisHeight = ca.height - this.gutterTop - this.gutterBottom;
564
+
565
+
566
+ // This must be here so that the two above variables are calculated
567
+ if (prop['chart.noaxes']) {
568
+ return;
569
+ }
570
+
571
+ co.moveTo(this.gutterLeft, Math.round( ca.height - this.gutterBottom));
572
+ co.lineTo(this.gutterLeft + this.axisWidth, Math.round( ca.height - this.gutterBottom));
573
+
574
+ co.moveTo(ma.round( this.gutterLeft + this.axisWidth), ca.height - this.gutterBottom);
575
+ co.lineTo(ma.round( this.gutterLeft + this.axisWidth), this.gutterTop);
576
+
577
+ co.stroke();
578
+
579
+
580
+ // Draw the right set of axes
581
+ co.beginPath();
582
+
583
+ var x = this.gutterLeft + this.axisWidth + prop['chart.gutter.center'];
584
+
585
+ co.moveTo(Math.round( x), this.gutterTop);
586
+ co.lineTo(Math.round( x), ca.height - this.gutterBottom);
587
+
588
+ co.moveTo(Math.round( x), Math.round( ca.height - this.gutterBottom));
589
+ co.lineTo(ca.width - this.gutterRight, Math.round( ca.height - this.gutterBottom));
590
+
591
+ co.stroke();
592
+ };
593
+
594
+
595
+
596
+
597
+ /**
598
+ * Draws the tick marks on the axes
599
+ */
600
+ this.drawTicks =
601
+ this.DrawTicks = function ()
602
+ {
603
+ // Set the linewidth
604
+ co.lineWidth = prop['chart.axis.linewidth'] + 0.001;
605
+
606
+ var numDataPoints = this.left.length;
607
+ var barHeight = ( (ca.height - this.gutterTop - this.gutterBottom)- (this.left.length * (prop['chart.margin'] * 2) )) / numDataPoints;
608
+
609
+ // Store this for later
610
+ this.barHeight = barHeight;
611
+
612
+ // If no axes - no tickmarks
613
+ if (prop['chart.noaxes']) {
614
+ return;
615
+ }
616
+
617
+ // Draw the left Y tick marks
618
+ if (prop['chart.numyticks'] > 0) {
619
+ co.beginPath();
620
+ for (var i=0; i<prop['chart.numyticks']; ++i) {
621
+ var y = prop['chart.gutter.top'] + (((ca.height - this.gutterTop - this.gutterBottom) / prop['chart.numyticks']) * i);
622
+ co.moveTo(this.gutterLeft + this.axisWidth , y);
623
+ co.lineTo(this.gutterLeft + this.axisWidth + 3, y);
624
+ }
625
+ co.stroke();
626
+
627
+ //Draw the right axis Y tick marks
628
+ co.beginPath();
629
+ for (var i=0; i<prop['chart.numyticks']; ++i) {
630
+ var y = prop['chart.gutter.top'] + (((ca.height - this.gutterTop - this.gutterBottom) / prop['chart.numyticks']) * i);
631
+ co.moveTo(this.gutterLeft + this.axisWidth + prop['chart.gutter.center'], y);
632
+ co.lineTo(this.gutterLeft + this.axisWidth + prop['chart.gutter.center'] - 3, y);
633
+ }
634
+ co.stroke();
635
+ }
636
+
637
+
638
+
639
+ /**
640
+ * X tickmarks
641
+ */
642
+ if (prop['chart.numxticks'] > 0) {
643
+ var xInterval = this.axisWidth / prop['chart.numxticks'];
644
+
645
+ // Is chart.xtickinterval specified ? If so, use that.
646
+ if (typeof(prop['chart.xtickinterval']) == 'number') {
647
+ xInterval = prop['chart.xtickinterval'];
648
+ }
649
+
650
+
651
+ // Draw the left sides X tick marks
652
+ for (i=this.gutterLeft; i<(this.gutterLeft + this.axisWidth); i+=xInterval) {
653
+ co.beginPath();
654
+ co.moveTo(Math.round( i), ca.height - this.gutterBottom);
655
+ co.lineTo(Math.round( i), (ca.height - this.gutterBottom) + 4);
656
+ co.closePath();
657
+
658
+ co.stroke();
659
+ }
660
+
661
+ // Draw the right sides X tick marks
662
+ var stoppingPoint = ca.width - this.gutterRight;
663
+
664
+ for (i=(this.gutterLeft + this.axisWidth + prop['chart.gutter.center'] + xInterval); i<=stoppingPoint; i+=xInterval) {
665
+ co.beginPath();
666
+ co.moveTo(Math.round(i), ca.height - this.gutterBottom);
667
+ co.lineTo(Math.round(i), (ca.height - this.gutterBottom) + 4);
668
+ co.closePath();
669
+
670
+ co.stroke();
671
+ }
672
+ }
673
+ };
674
+
675
+
676
+
677
+
678
+ /**
679
+ * Figures out the maximum value, or if defined, uses xmax
680
+ */
681
+ this.getMax =
682
+ this.GetMax = function()
683
+ {
684
+ var dec = prop['chart.scale.decimals'];
685
+
686
+ // chart.xmax defined
687
+ if (prop['chart.xmax']) {
688
+
689
+ var max = prop['chart.xmax'];
690
+ var min = prop['chart.xmin'];
691
+
692
+ this.scale2 = RG.getScale2(this, {
693
+ 'max':max,
694
+ 'min':min,
695
+ 'strict': true,
696
+ 'scale.thousand':prop['chart.scale.thousand'],
697
+ 'scale.point':prop['chart.scale.point'],
698
+ 'scale.decimals':prop['chart.scale.decimals'],
699
+ 'ylabels.count':prop['chart.labels.count'],
700
+ 'scale.round':prop['chart.scale.round'],
701
+ 'units.pre': prop['chart.units.pre'],
702
+ 'units.post': prop['chart.units.post']
703
+ });
704
+ this.max = this.scale2.max;
705
+ this.min = this.scale2.min;
706
+
707
+
708
+ /**
709
+ * Generate the scale ourselves
710
+ */
711
+ } else {
712
+
713
+ var max = Math.max(RG.array_max(this.left), RG.array_max(this.right));
714
+
715
+ this.scale2 = RG.getScale2(this, {
716
+ 'max':max,
717
+ //'strict': true,
718
+ 'min':prop['chart.xmin'],
719
+ 'scale.thousand':prop['chart.scale.thousand'],
720
+ 'scale.point':prop['chart.scale.point'],
721
+ 'scale.decimals':prop['chart.scale.decimals'],
722
+ 'ylabels.count':prop['chart.labels.count'],
723
+ 'scale.round':prop['chart.scale.round'],
724
+ 'units.pre': prop['chart.units.pre'],
725
+ 'units.post': prop['chart.units.post']
726
+ });
727
+
728
+
729
+ this.max = this.scale2.max;
730
+ this.min = this.scale2.min;
731
+ }
732
+
733
+ // Don't need to return it as it is stored in this.max
734
+ };
735
+
736
+
737
+
738
+
739
+ /**
740
+ * Function to draw the left hand bars
741
+ */
742
+ this.drawLeftBars =
743
+ this.DrawLeftBars = function ()
744
+ {
745
+ var opt = {};
746
+
747
+ if (typeof arguments[0] === 'object') {
748
+ opt.shadow = arguments[0].shadow;
749
+ } else {
750
+ opt.shadow = true;
751
+ }
752
+
753
+ var offsetx = prop['chart.variant.threed.offsetx'],
754
+ offsety = prop['chart.variant.threed.offsety'];
755
+
756
+ // Set the stroke colour
757
+ co.strokeStyle = prop['chart.strokestyle'];
758
+
759
+ // Set the linewidth
760
+ co.lineWidth = prop['chart.linewidth'];
761
+
762
+ for (var i=(this.left.length - 1); i>=0; i-=1) {
763
+
764
+ /**
765
+ * Turn on a shadow if requested
766
+ */
767
+ if (prop['chart.shadow'] && prop['chart.variant'] !== '3d' && opt.shadow) {
768
+ co.shadowColor = prop['chart.shadow.color'];
769
+ co.shadowBlur = prop['chart.shadow.blur'];
770
+ co.shadowOffsetX = prop['chart.shadow.offsetx'];
771
+ co.shadowOffsetY = prop['chart.shadow.offsety'];
772
+ }
773
+
774
+
775
+
776
+
777
+ // If chart.colors.sequential is specified - handle that
778
+ // ** There's another instance of this further down **
779
+ if (prop['chart.colors.sequential']) {
780
+ co.fillStyle = prop['chart.colors'][i];
781
+
782
+ } else {
783
+ co.fillStyle = prop['chart.colors'][0];
784
+ }
785
+
786
+
787
+
788
+
789
+ /**
790
+ * Work out the coordinates
791
+ */
792
+
793
+ var width = (( (this.left[i] - this.min) / (this.max - this.min)) * this.axisWidth);
794
+
795
+ var coords = [
796
+ ma.round( this.gutterLeft + this.axisWidth - width),
797
+ ma.round( this.gutterTop + (i * ( this.axisHeight / this.left.length)) + prop['chart.margin']),
798
+ width,
799
+ this.barHeight
800
+ ];
801
+
802
+ // Draw the IE shadow if necessary
803
+ if (RG.ISOLD && prop['chart.shadow']) {
804
+ this.drawIEShadow(coords);
805
+ }
806
+
807
+
808
+ if (this.left[i] !== null) {
809
+ co.strokeRect(coords[0], coords[1], coords[2], coords[3]);
810
+ co.fillRect(coords[0], coords[1], coords[2], coords[3]);
811
+ }
812
+
813
+
814
+
815
+
816
+
817
+
818
+
819
+
820
+
821
+
822
+
823
+
824
+
825
+
826
+
827
+
828
+ // Draw the 3D sides if required
829
+ if (prop['chart.variant'] === '3d' && this.left[i] !== null) {
830
+
831
+ // If the shadow is enabled draw the backface for
832
+ // (that we don't actually see
833
+ if (prop['chart.shadow'] && opt.shadow) {
834
+
835
+ co.shadowColor = prop['chart.shadow.color'];
836
+ co.shadowBlur = prop['chart.shadow.blur'];
837
+ co.shadowOffsetX = prop['chart.shadow.offsetx'];
838
+ co.shadowOffsetY = prop['chart.shadow.offsety'];
839
+
840
+
841
+ pa2(co,
842
+ 'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',
843
+ coords[0] + offsetx, coords[1] - offsety,
844
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
845
+ coords[0] + offsetx + coords[2], coords[1] - offsety + coords[3],
846
+ coords[0] + offsetx,coords[1] - offsety + coords[3]
847
+ );
848
+ }
849
+
850
+
851
+
852
+ // If chart.colors.sequential is specified - handle that (again)
853
+ //
854
+ // ** There's another instance of this further up **
855
+ if (prop['chart.colors.sequential']) {
856
+ co.fillStyle = prop['chart.colors'][i];
857
+
858
+ } else {
859
+ co.fillStyle = prop['chart.colors'][0];
860
+ }
861
+
862
+ pa2(co,
863
+ 'b m % % l % % l % % l % % f %',
864
+ coords[0],coords[1],
865
+ coords[0] + offsetx, coords[1] - offsety,
866
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
867
+ coords[0] + coords[2], coords[1]
868
+ );
869
+
870
+ pa2(co,
871
+ 'b m % % l % % l % % l % % f rgba(255,255,255,0.4)',
872
+ coords[0],coords[1],
873
+ coords[0] + offsetx, coords[1] - offsety,
874
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
875
+ coords[0] + coords[2], coords[1]
876
+ );
877
+ }
878
+
879
+ this.draw3DLeftVerticalAxis();
880
+
881
+
882
+
883
+
884
+
885
+
886
+
887
+
888
+
889
+
890
+
891
+
892
+
893
+
894
+
895
+ // Add the coordinates to the coords array
896
+ this.coords.push([coords[0],coords[1],coords[2],coords[3]]);
897
+ this.coordsLeft.push([coords[0],coords[1],coords[2],coords[3]]);
898
+ }
899
+
900
+ /**
901
+ * Turn off any shadow
902
+ */
903
+ RG.noShadow(this);
904
+
905
+ // Reset the linewidth
906
+ co.lineWidth = 1;
907
+ };
908
+
909
+
910
+
911
+
912
+ /**
913
+ * Function to draw the right hand bars
914
+ */
915
+ this.drawRightBars =
916
+ this.DrawRightBars = function ()
917
+ {
918
+ var opt = {};
919
+
920
+ if (typeof arguments[0] === 'object') {
921
+ opt.shadow = arguments[0].shadow;
922
+ } else {
923
+ opt.shadow = true;
924
+ }
925
+
926
+ var offsetx = prop['chart.variant.threed.offsetx'],
927
+ offsety = prop['chart.variant.threed.offsety'];
928
+
929
+
930
+
931
+
932
+ // Set the stroke colour
933
+ co.strokeStyle = prop['chart.strokestyle'];
934
+
935
+ // Set the linewidth
936
+ co.lineWidth = prop['chart.linewidth'];
937
+
938
+ /**
939
+ * Turn on a shadow if requested
940
+ */
941
+ if (prop['chart.shadow'] && prop['chart.variant'] !== '3d' && opt.shadow) {
942
+ co.shadowColor = prop['chart.shadow.color'];
943
+ co.shadowBlur = prop['chart.shadow.blur'];
944
+ co.shadowOffsetX = prop['chart.shadow.offsetx'];
945
+ co.shadowOffsetY = prop['chart.shadow.offsety'];
946
+ }
947
+
948
+ for (var i=(this.right.length - 1); i>=0; i-=1) {
949
+
950
+
951
+ // If chart.colors.sequential is specified - handle that
952
+ if (prop['chart.colors.sequential']) {
953
+ co.fillStyle = prop['chart.colors'][i];
954
+
955
+ } else {
956
+ co.fillStyle = prop['chart.colors'][0];
957
+ }
958
+
959
+
960
+ var width = (((this.right[i] - this.min) / (this.max - this.min)) * this.axisWidth);
961
+
962
+ var coords = [
963
+ ma.round( this.gutterLeft + this.axisWidth + prop['chart.gutter.center']),
964
+ ma.round( prop['chart.margin'] + (i * (this.axisHeight / this.right.length)) + this.gutterTop),
965
+ width,
966
+ this.barHeight
967
+ ];
968
+
969
+ // Draw the IE shadow if necessary
970
+ if (RG.ISOLD && prop['chart.shadow']) {
971
+ this.DrawIEShadow(coords);
972
+ }
973
+
974
+ if (this.right[i] !== null) {
975
+ co.strokeRect(ma.round( coords[0]), Math.round( coords[1]), coords[2], coords[3]);
976
+ co.fillRect(ma.round( coords[0]), Math.round( coords[1]), coords[2], coords[3]);
977
+ }
978
+
979
+
980
+
981
+
982
+
983
+
984
+
985
+
986
+
987
+
988
+
989
+
990
+
991
+ // Draw the 3D sides if required
992
+ if (prop['chart.variant'] === '3d' && this.right[i] !== null) {
993
+
994
+ var color = co.fillStyle;
995
+
996
+
997
+ // If the shadow is enabled draw the backface for
998
+ // (that we don't actually see
999
+ if (prop['chart.shadow'] && opt.shadow) {
1000
+
1001
+ co.shadowColor = prop['chart.shadow.color'];
1002
+ co.shadowBlur = prop['chart.shadow.blur'];
1003
+ co.shadowOffsetX = prop['chart.shadow.offsetx'];
1004
+ co.shadowOffsetY = prop['chart.shadow.offsety'];
1005
+
1006
+ pa2(co,
1007
+ 'b m % % l % % l % % l % % f black sc rgba(0,0,0,0) sx 0 sy 0 sb 0',
1008
+ coords[0] + offsetx, coords[1] - offsety,
1009
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
1010
+ coords[0] + offsetx + coords[2], coords[1] - offsety + coords[3],
1011
+ coords[0] + offsetx,coords[1] - offsety + coords[3]
1012
+ );
1013
+ }
1014
+
1015
+ // Draw the top
1016
+ pa2(co,
1017
+ 'b m % % l % % l % % l % % f %',
1018
+ coords[0],coords[1],
1019
+ coords[0] + offsetx, coords[1] - offsety,
1020
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
1021
+ coords[0] + coords[2], coords[1],
1022
+ color
1023
+ );
1024
+
1025
+
1026
+ // Draw the right hand side
1027
+ pa2(co,
1028
+ 'b m % % l % % l % % l % % f %',
1029
+ coords[0] + coords[2],coords[1],
1030
+ coords[0] + coords[2] + offsetx, coords[1] - offsety,
1031
+ coords[0] + coords[2] + offsetx, coords[1] - offsety + coords[3],
1032
+ coords[0] + coords[2],coords[1] + coords[3],
1033
+ color
1034
+ );
1035
+
1036
+ // Draw the LIGHTER top
1037
+ pa2(co,
1038
+ 'b m % % l % % l % % l % % f rgba(255,255,255,0.6)',
1039
+ coords[0],coords[1],
1040
+ coords[0] + offsetx, coords[1] - offsety,
1041
+ coords[0] + offsetx + coords[2], coords[1] - offsety,
1042
+ coords[0] + coords[2], coords[1]
1043
+ );
1044
+
1045
+
1046
+ // Draw the DARKER right hand side
1047
+ pa2(co,
1048
+ 'b m % % l % % l % % l % % f rgba(0,0,0,0.3)',
1049
+ coords[0] + coords[2],coords[1],
1050
+ coords[0] + coords[2] + offsetx, coords[1] - offsety,
1051
+ coords[0] + coords[2] + offsetx, coords[1] - offsety + coords[3],
1052
+ coords[0] + coords[2],coords[1] + coords[3]
1053
+ );
1054
+ }
1055
+
1056
+
1057
+
1058
+
1059
+
1060
+
1061
+
1062
+
1063
+
1064
+
1065
+
1066
+
1067
+
1068
+ /**
1069
+ * Add the coordinates to the coords array
1070
+ */
1071
+ this.coords.push([coords[0],coords[1],coords[2],coords[3]]);
1072
+ this.coordsRight.push([coords[0],coords[1],coords[2],coords[3]]);
1073
+ }
1074
+
1075
+
1076
+
1077
+
1078
+
1079
+
1080
+
1081
+
1082
+
1083
+
1084
+
1085
+
1086
+
1087
+
1088
+
1089
+
1090
+
1091
+
1092
+
1093
+
1094
+
1095
+
1096
+
1097
+
1098
+
1099
+
1100
+
1101
+ /**
1102
+ * Turn off any shadow
1103
+ */
1104
+ RG.NoShadow(this);
1105
+
1106
+ // Reset the linewidth
1107
+ co.lineWidth = 1;
1108
+ };
1109
+
1110
+
1111
+
1112
+
1113
+ /**
1114
+ * Draws the titles
1115
+ */
1116
+ this.drawLabels =
1117
+ this.DrawLabels = function ()
1118
+ {
1119
+
1120
+ var font = prop['chart.text.font'],
1121
+ color = prop['chart.labels.color'] || prop['chart.text.color'],
1122
+ size = prop['chart.text.size'],
1123
+ labels = prop['chart.labels'],
1124
+ barAreaHeight = ca.height - this.gutterTop - this.gutterBottom
1125
+
1126
+ co.fillStyle = color;
1127
+
1128
+ for (var i=0,len=labels.length; i<len; i+=1) {
1129
+ RG.Text2(this, {
1130
+ 'color': color,
1131
+ 'font':font,
1132
+ 'size':size,
1133
+ 'x':this.gutterLeft + this.axisWidth + (prop['chart.gutter.center'] / 2),
1134
+ 'y':this.gutterTop + ((barAreaHeight / labels.length) * (i)) + ((barAreaHeight / labels.length) / 2),
1135
+ 'text':String(labels[i] ? String(labels[i]) : ''),
1136
+ 'halign':'center',
1137
+ 'valign':'center',
1138
+ 'marker':false,
1139
+ 'tag': 'labels'
1140
+ });
1141
+ }
1142
+
1143
+
1144
+
1145
+ co.fillStyle = prop['chart.text.color'];
1146
+
1147
+
1148
+
1149
+ if (prop['chart.xlabels']) {
1150
+
1151
+ var grapharea = (ca.width - prop['chart.gutter.center'] - this.gutterLeft - this.gutterRight) / 2;
1152
+
1153
+ // Now draw the X labels for the left hand side
1154
+ for (var i=0; i<this.scale2.labels.length; ++i) {
1155
+ RG.text2(this, {
1156
+ 'font':font,
1157
+ 'size':size,
1158
+ 'x':this.gutterLeft + ((grapharea / this.scale2.labels.length) * i),
1159
+ 'y':ca.height - this.gutterBottom + 3,
1160
+ 'text':this.scale2.labels[this.scale2.labels.length - i - 1],
1161
+ 'valign':'top',
1162
+ 'halign':'center',
1163
+ 'tag': 'scale'
1164
+ });
1165
+
1166
+
1167
+
1168
+
1169
+ // Draw the scale for the right hand side
1170
+ RG.text2(this, {
1171
+ 'font':font,
1172
+ 'size':size,
1173
+ 'x':this.gutterLeft+ grapharea + prop['chart.gutter.center'] + ((grapharea / this.scale2.labels.length) * (i + 1)),
1174
+ 'y':ca.height - this.gutterBottom + 3,
1175
+ 'text':this.scale2.labels[i],
1176
+ 'valign':'top',
1177
+ 'halign':'center',
1178
+ 'tag': 'scale'
1179
+ });
1180
+ }
1181
+
1182
+
1183
+
1184
+
1185
+ // Draw zero?
1186
+ if (prop['chart.scale.zerostart']) {
1187
+ RG.text2(this, {
1188
+ 'font':font,
1189
+ 'size':size,
1190
+ 'x':this.gutterLeft + this.axisWidth,
1191
+ 'y':ca.height - this.gutterBottom + 3,
1192
+ 'text':'0',
1193
+ 'valign':'top',
1194
+ 'halign':'center',
1195
+ 'tag': 'scale'
1196
+ });
1197
+
1198
+
1199
+ RG.text2(this, {
1200
+ 'font':font,
1201
+ 'size':size,
1202
+ 'x':this.gutterLeft + this.axisWidth + this.gutterCenter,
1203
+ 'y':ca.height - this.gutterBottom + 3,
1204
+ 'text':'0',
1205
+ 'valign':'top',
1206
+ 'halign':'center',
1207
+ 'tag': 'scale'
1208
+ });
1209
+ }
1210
+ }
1211
+
1212
+ /**
1213
+ * Draw above labels
1214
+ */
1215
+ if (prop['chart.labels.above']) {
1216
+
1217
+ // Draw the left sides above labels
1218
+
1219
+ var coordsLeft = RG.arrayReverse(this.coordsLeft);
1220
+
1221
+ for (var i=0; i<coordsLeft.length; ++i) {
1222
+
1223
+ if (typeof this.left[i] !== 'number') {
1224
+ continue;
1225
+ }
1226
+
1227
+ var coords = coordsLeft[i];
1228
+
1229
+ RG.text2(this, {
1230
+ font:font,
1231
+ size:size,
1232
+ x:coords[0] - 5,
1233
+ y:coords[1] + (coords[3] / 2),
1234
+ text:RG.numberFormat(
1235
+ this,
1236
+ this.left[i],
1237
+ prop['chart.units.pre'],
1238
+ prop['chart.units.post']
1239
+ ),
1240
+ valign:'center',
1241
+ halign:'right',
1242
+ tag:'labels.above'
1243
+ });
1244
+ }
1245
+
1246
+
1247
+
1248
+
1249
+
1250
+
1251
+
1252
+
1253
+ // Draw the right sides above labels
1254
+
1255
+ var coordsRight = RG.arrayReverse(this.coordsRight);
1256
+
1257
+ for (i=0; i<coordsRight.length; ++i) {
1258
+
1259
+ if (typeof this.right[i] != 'number') {
1260
+ continue;
1261
+ }
1262
+
1263
+ var coords = coordsRight[i];
1264
+
1265
+ RG.Text2(this, {
1266
+ 'font':font,
1267
+ 'size':size,
1268
+ 'x':coords[0] + coords[2] + 5,
1269
+ 'y':coords[1] + (coords[3] / 2),
1270
+ 'text':RG.number_format(this, this.right[i], prop['chart.units.pre'], prop['chart.units.post']),
1271
+ 'valign':'center',
1272
+ 'halign':'left',
1273
+ 'tag': 'labels.above'
1274
+ });
1275
+ }
1276
+ }
1277
+ };
1278
+
1279
+
1280
+
1281
+
1282
+ /**
1283
+ * Draws the titles
1284
+ */
1285
+ this.drawTitles =
1286
+ this.DrawTitles = function ()
1287
+ {
1288
+ RG.Text2(this, {
1289
+ 'font':prop['chart.text.font'],
1290
+ 'size':prop['chart.text.size'],
1291
+ 'x':this.gutterLeft + 5,
1292
+ 'y':this.gutterTop - 5,
1293
+ 'text':String(prop['chart.title.left']),
1294
+ 'halign':'left',
1295
+ 'valign':'bottom',
1296
+ 'tag': 'title.left'
1297
+ });
1298
+
1299
+ RG.Text2(this, {
1300
+ 'font':prop['chart.text.font'],
1301
+ 'size':prop['chart.text.size'],
1302
+ 'x': ca.width - this.gutterRight - 5,
1303
+ 'y':this.gutterTop - 5,
1304
+ 'text':String(prop['chart.title.right']),
1305
+ 'halign':'right',
1306
+ 'valign':'bottom',
1307
+ 'tag': 'title.right'
1308
+ });
1309
+
1310
+
1311
+
1312
+ // Draw the main title for the whole chart
1313
+ RG.drawTitle(
1314
+ this,
1315
+ prop['chart.title'],
1316
+ this.gutterTop,
1317
+ null,
1318
+ prop['chart.title.size'] ? prop['chart.title.size'] : null
1319
+ );
1320
+ };
1321
+
1322
+
1323
+
1324
+
1325
+ /**
1326
+ * This function is used by MSIE only to manually draw the shadow
1327
+ *
1328
+ * @param array coords The coords for the bar
1329
+ */
1330
+ this.drawIEShadow =
1331
+ this.DrawIEShadow = function (coords)
1332
+ {
1333
+ var prevFillStyle = co.fillStyle;
1334
+ var offsetx = prop['chart.shadow.offsetx'];
1335
+ var offsety = prop['chart.shadow.offsety'];
1336
+
1337
+ co.lineWidth = prop['chart.linewidth'];
1338
+ co.fillStyle = prop['chart.shadow.color'];
1339
+ co.beginPath();
1340
+
1341
+ // Draw shadow here
1342
+ co.fillRect(coords[0] + offsetx, coords[1] + offsety, coords[2],coords[3]);
1343
+
1344
+ co.fill();
1345
+
1346
+ // Change the fillstyle back to what it was
1347
+ co.fillStyle = prevFillStyle;
1348
+ }
1349
+
1350
+
1351
+
1352
+
1353
+ /**
1354
+ * Returns the appropriate focussed bar coordinates
1355
+ *
1356
+ * @param e object The event object
1357
+ */
1358
+ this.getShape =
1359
+ this.getBar = function (e)
1360
+ {
1361
+ var canvas = this.canvas,
1362
+ context = this.context,
1363
+ mouseCoords = RG.getMouseXY(e)
1364
+
1365
+ /**
1366
+ * Loop through the bars determining if the mouse is over a bar
1367
+ */
1368
+ for (var i=0; i<this.coords.length; i++) {
1369
+
1370
+ var mouseX = mouseCoords[0],
1371
+ mouseY = mouseCoords[1],
1372
+ left = this.coords[i][0],
1373
+ top = this.coords[i][1],
1374
+ width = this.coords[i][2],
1375
+ height = this.coords[i][3]
1376
+
1377
+ //if (mouseX >= left && mouseX <= (left + width) && mouseY >= top && mouseY <= (top + height) ) {
1378
+ pa2(co,
1379
+ 'b r % % % %',
1380
+ left,
1381
+ top,
1382
+ width,
1383
+ height
1384
+ );
1385
+
1386
+ if (co.isPointInPath(mouseX, mouseY)) {
1387
+
1388
+ var tooltip = RG.parseTooltipText(prop['chart.tooltips'], i);
1389
+
1390
+ return {
1391
+ 0: this,1: left,2: top,3: width,4: height,5: i,
1392
+ 'object': this, 'x': left, 'y': top, 'width': width, 'height': height, 'index': i, 'tooltip': tooltip
1393
+ };
1394
+ }
1395
+ }
1396
+
1397
+ return null;
1398
+ };
1399
+
1400
+
1401
+
1402
+
1403
+ /**
1404
+ * Each object type has its own Highlight() function which highlights the appropriate shape
1405
+ *
1406
+ * @param object shape The shape to highlight
1407
+ */
1408
+ this.highlight =
1409
+ this.Highlight = function (shape)
1410
+ {
1411
+ if (typeof prop['chart.highlight.style'] === 'function') {
1412
+ (prop['chart.highlight.style'])(shape);
1413
+ } else {
1414
+ RG.Highlight.Rect(this, shape);
1415
+ }
1416
+ };
1417
+
1418
+
1419
+
1420
+
1421
+ /**
1422
+ * When you click on the canvas, this will return the relevant value (if any)
1423
+ *
1424
+ * REMEMBER This function will need updating if the Bipolar ever gets chart.ymin
1425
+ *
1426
+ * @param object e The event object
1427
+ */
1428
+ this.getValue = function (e)
1429
+ {
1430
+ var obj = e.target.__object__;
1431
+ var mouseXY = RG.getMouseXY(e);
1432
+ var mouseX = mouseXY[0];
1433
+
1434
+ /**
1435
+ * Left hand side
1436
+ */
1437
+ if (mouseX > this.gutterLeft && mouseX < ( (ca.width / 2) - (prop['chart.gutter.center'] / 2) )) {
1438
+ var value = (mouseX - prop['chart.gutter.left']) / this.axisWidth;
1439
+ value = this.max - (value * this.max);
1440
+ }
1441
+
1442
+ /**
1443
+ * Right hand side
1444
+ */
1445
+ if (mouseX < (ca.width - this.gutterRight) && mouseX > ( (ca.width / 2) + (prop['chart.gutter.center'] / 2) )) {
1446
+ var value = (mouseX - prop['chart.gutter.left'] - this.axisWidth - prop['chart.gutter.center']) / this.axisWidth;
1447
+ value = (value * this.max);
1448
+ }
1449
+
1450
+ return value;
1451
+ };
1452
+
1453
+
1454
+
1455
+
1456
+ /**
1457
+ * The getObjectByXY() worker method. Don't call this call:
1458
+ *
1459
+ * RGraph.ObjectRegistry.getObjectByXY(e)
1460
+ *
1461
+ * @param object e The event object
1462
+ */
1463
+ this.getObjectByXY = function (e)
1464
+ {
1465
+ var mouseXY = RG.getMouseXY(e);
1466
+
1467
+ // Adjust the mouse Y coordinate for when the bar chart is
1468
+ // a 3D variant
1469
+
1470
+ if (prop['chart.variant'] === '3d') {
1471
+ var adjustment = prop['chart.variant.threed.angle'] * mouseXY[0];
1472
+ mouseXY[1] -= adjustment;
1473
+ }
1474
+
1475
+
1476
+
1477
+ if (
1478
+ mouseXY[0] > prop['chart.gutter.left']
1479
+ && mouseXY[0] < (ca.width - prop['chart.gutter.right'])
1480
+ && mouseXY[1] > prop['chart.gutter.top']
1481
+ && mouseXY[1] < (ca.height - prop['chart.gutter.bottom'])
1482
+ ) {
1483
+
1484
+ return this;
1485
+ }
1486
+ };
1487
+
1488
+
1489
+
1490
+
1491
+ /**
1492
+ * This function positions a tooltip when it is displayed
1493
+ *
1494
+ * @param obj object The chart object
1495
+ * @param int x The X coordinate specified for the tooltip
1496
+ * @param int y The Y coordinate specified for the tooltip
1497
+ * @param objec tooltip The tooltips DIV element
1498
+ *
1499
+ this.positionTooltip = function (obj, x, y, tooltip, idx)
1500
+ {
1501
+ var coordX = obj.coords[tooltip.__index__][0],
1502
+ coordY = obj.coords[tooltip.__index__][1],
1503
+ coordW = obj.coords[tooltip.__index__][2],
1504
+ coordH = obj.coords[tooltip.__index__][3],
1505
+ canvasXY = RG.getCanvasXY(obj.canvas),
1506
+ mouseXY = RG.getMouseXY(window.event),
1507
+ gutterLeft = obj.Get('chart.gutter.left'),
1508
+ gutterTop = obj.Get('chart.gutter.top'),
1509
+ width = tooltip.offsetWidth,
1510
+ height = tooltip.offsetHeight
1511
+
1512
+ // If the chart is a 3D version the tooltip Y position needs this
1513
+ // adjustment
1514
+ if (prop['chart.variant'] === '3d' && mouseXY) {
1515
+ var adjustment = (prop['chart.variant.threed.angle'] * mouseXY[0]);
1516
+ }
1517
+
1518
+ // Set the top position
1519
+ tooltip.style.left = 0;
1520
+ tooltip.style.top = window.event.pageY - height - 5 + 'px';
1521
+
1522
+
1523
+ // By default any overflow is hidden
1524
+ tooltip.style.overflow = '';
1525
+
1526
+ // LEFT edge
1527
+ if (canvasXY[0] + mouseXY[0] - (width / 2) < 0) {
1528
+ tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.1) + 'px';
1529
+
1530
+ // RIGHT edge
1531
+ } else if (canvasXY[0] + mouseXY[0] + (width / 2) > doc.body.offsetWidth) {
1532
+ tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.9) + 'px';
1533
+
1534
+ // Default positioning - CENTERED
1535
+ } else {
1536
+ tooltip.style.left = canvasXY[0] + mouseXY[0] - (width / 2) + 'px';
1537
+ }
1538
+ };*/
1539
+
1540
+
1541
+
1542
+
1543
+ /**
1544
+ * Returns the X coords for a value. Returns two coords because there are... two scales.
1545
+ *
1546
+ * @param number value The value to get the coord for
1547
+ */
1548
+ this.getXCoord = function (value)
1549
+ {
1550
+ if (value > this.max || value < 0) {
1551
+ return null;
1552
+ }
1553
+
1554
+ var ret = [];
1555
+
1556
+ // The offset into the graph area
1557
+ var offset = ((value / this.max) * this.axisWidth);
1558
+
1559
+ // Get the coords (one fo each side)
1560
+ ret[0] = (this.gutterLeft + this.axisWidth) - offset;
1561
+ ret[1] = (ca.width - this.gutterRight - this.axisWidth) + offset;
1562
+
1563
+ return ret;
1564
+ };
1565
+
1566
+
1567
+
1568
+
1569
+ /**
1570
+ * This allows for easy specification of gradients
1571
+ */
1572
+ this.parseColors = function ()
1573
+ {
1574
+ // Save the original colors so that they can be restored when the canvas is reset
1575
+ if (this.original_colors.length === 0) {
1576
+ this.original_colors['chart.colors'] = RG.array_clone(prop['chart.colors']);
1577
+ this.original_colors['chart.highlight.stroke'] = RG.array_clone(prop['chart.highlight.fill']);
1578
+ this.original_colors['chart.highlight.fill'] = RG.array_clone(prop['chart.highlight.fill']);
1579
+ this.original_colors['chart.axis.color'] = RG.array_clone(prop['chart.axis.color']);
1580
+ this.original_colors['chart.strokestyle'] = RG.array_clone(prop['chart.strokestyle']);
1581
+ }
1582
+
1583
+ var props = this.properties;
1584
+ var colors = props['chart.colors'];
1585
+
1586
+ for (var i=0; i<colors.length; ++i) {
1587
+ colors[i] = this.parseSingleColorForGradient(colors[i]);
1588
+ }
1589
+
1590
+ props['chart.highlight.stroke'] = this.parseSingleColorForGradient(props['chart.highlight.stroke']);
1591
+ props['chart.highlight.fill'] = this.parseSingleColorForGradient(props['chart.highlight.fill']);
1592
+ props['chart.axis.color'] = this.parseSingleColorForGradient(props['chart.axis.color']);
1593
+ props['chart.strokestyle'] = this.parseSingleColorForGradient(props['chart.strokestyle']);
1594
+ };
1595
+
1596
+
1597
+
1598
+
1599
+ /**
1600
+ * Use this function to reset the object to the post-constructor state. Eg reset colors if
1601
+ * need be etc
1602
+ */
1603
+ this.reset = function ()
1604
+ {
1605
+ };
1606
+
1607
+
1608
+
1609
+
1610
+ /**
1611
+ * This parses a single color value
1612
+ */
1613
+ this.parseSingleColorForGradient = function (color)
1614
+ {
1615
+ if (!color || typeof(color) != 'string') {
1616
+ return color;
1617
+ }
1618
+
1619
+ if (color.match(/^gradient\((.*)\)$/i)) {
1620
+
1621
+ var parts = RegExp.$1.split(':');
1622
+
1623
+ // Create the gradient
1624
+ var grad = co.createLinearGradient(prop['chart.gutter.left'],0,ca.width - prop['chart.gutter.right'],0);
1625
+
1626
+ var diff = 1 / (parts.length - 1);
1627
+
1628
+ grad.addColorStop(0, RG.trim(parts[0]));
1629
+
1630
+ for (var j=1; j<parts.length; ++j) {
1631
+ grad.addColorStop(j * diff, RG.trim(parts[j]));
1632
+ }
1633
+ }
1634
+
1635
+ return grad ? grad : color;
1636
+ };
1637
+
1638
+
1639
+
1640
+
1641
+ /**
1642
+ * Using a function to add events makes it easier to facilitate method chaining
1643
+ *
1644
+ * @param string type The type of even to add
1645
+ * @param function func
1646
+ */
1647
+ this.on = function (type, func)
1648
+ {
1649
+ if (type.substr(0,2) !== 'on') {
1650
+ type = 'on' + type;
1651
+ }
1652
+
1653
+ if (typeof this[type] !== 'function') {
1654
+ this[type] = func;
1655
+ } else {
1656
+ RG.addCustomEventListener(this, type, func);
1657
+ }
1658
+
1659
+ return this;
1660
+ };
1661
+
1662
+
1663
+
1664
+
1665
+ //
1666
+ // Draw the background grid
1667
+ //
1668
+ this.drawBackgroundGrid = function ()
1669
+ {
1670
+ if (prop['chart.background.grid']) {
1671
+
1672
+ var variant = prop['chart.variant'],
1673
+ color = prop['chart.background.grid.color'],
1674
+ numvlines = prop['chart.labels.count'],
1675
+ numhlines = this.left.length,
1676
+ vlines = prop['chart.background.grid.vlines'],
1677
+ hlines = prop['chart.background.grid.hlines'],
1678
+ linewidth = prop['chart.background.grid.linewidth'];
1679
+
1680
+ // Autofit
1681
+ if (typeof prop['chart.background.grid.autofit.numhlines'] === 'number') {
1682
+ numhlines = prop['chart.background.grid.autofit.numhlines'];
1683
+ }
1684
+
1685
+ if (typeof prop['chart.background.grid.autofit.numvlines'] === 'number') {
1686
+ numvlines = prop['chart.background.grid.autofit.numvlines'];
1687
+ }
1688
+
1689
+ co.lineWidth = linewidth;
1690
+
1691
+ // If it's a bar and 3D variant, translate
1692
+ if (variant == '3d') {
1693
+ co.save();
1694
+ co.translate(
1695
+ prop['chart.variant.threed.offsetx'],
1696
+ -1 * prop['chart.variant.threed.offsety']
1697
+ );
1698
+ }
1699
+
1700
+ // Draw vertical grid lines for the left side
1701
+ if (vlines) {
1702
+ for (var i=0; i<=numvlines; i+=1) {
1703
+ pa2(co,
1704
+ 'b m % % l % % s %',
1705
+ this.gutterLeft + (this.axisWidth / numvlines) * i, this.gutterTop,
1706
+ this.gutterLeft + (this.axisWidth / numvlines) * i, this.gutterTop + this.axisHeight,
1707
+ color
1708
+ );
1709
+
1710
+ }
1711
+ }
1712
+
1713
+ // Draw horizontal grid lines for the left side
1714
+ if (hlines) {
1715
+ for (var i=0; i<=numhlines; i+=1) {
1716
+ pa2(co,
1717
+ 'b m % % l % % s %',
1718
+ this.gutterLeft, this.gutterTop + (this.axisHeight / numhlines) * i,
1719
+ this.gutterLeft + this.axisWidth, this.gutterTop + (this.axisHeight / numhlines) * i,
1720
+ color
1721
+ );
1722
+ }
1723
+ }
1724
+
1725
+
1726
+ // Draw vertical grid lines for the right side
1727
+ if (vlines) {
1728
+ for (var i=0; i<=numvlines; i+=1) {
1729
+ pa2(co,
1730
+ 'b m % % l % % s %',
1731
+ this.gutterLeft + this.gutterCenter + this.axisWidth + (this.axisWidth / numvlines) * i, this.gutterTop,
1732
+ this.gutterLeft + this.gutterCenter + this.axisWidth + (this.axisWidth / numvlines) * i, this.gutterTop + this.axisHeight,
1733
+ color
1734
+ );
1735
+ }
1736
+ }
1737
+
1738
+ // Draw horizontal grid lines for the right side
1739
+ if (hlines) {
1740
+ for (var i=0; i<=numhlines; i+=1) {
1741
+ pa2(co,
1742
+ 'b m % % l % % s %',
1743
+ this.gutterLeft + this.axisWidth + this.gutterCenter, this.gutterTop + (this.axisHeight / numhlines) * i,
1744
+ this.gutterLeft + this.axisWidth + this.gutterCenter + this.axisWidth, this.gutterTop + (this.axisHeight / numhlines) * i,
1745
+ color
1746
+ );
1747
+ }
1748
+ }
1749
+
1750
+
1751
+ // If it's a bar and 3D variant, translate
1752
+ if (variant == '3d') {
1753
+ co.restore();
1754
+ }
1755
+ }
1756
+ };
1757
+
1758
+
1759
+
1760
+
1761
+ /**
1762
+ * This function runs once only
1763
+ * (put at the end of the file (before any effects))
1764
+ */
1765
+ this.firstDrawFunc = function ()
1766
+ {
1767
+ // Tooltips need reversing now because the bars
1768
+ // are drawn from the bottom up
1769
+ if (prop['chart.tooltips']) {
1770
+ prop['chart.tooltips'] = RG.arrayReverse(prop['chart.tooltips']);
1771
+ }
1772
+ };
1773
+
1774
+
1775
+
1776
+
1777
+
1778
+
1779
+
1780
+
1781
+ /**
1782
+ * Objects are now always registered so that when RGraph.Redraw()
1783
+ * is called this chart will be redrawn.
1784
+ */
1785
+ RG.Register(this);
1786
+
1787
+
1788
+
1789
+
1790
+ /**
1791
+ * This is the 'end' of the constructor so if the first argument
1792
+ * contains configuration dsta - handle that.
1793
+ */
1794
+ if (parseConfObjectForOptions) {
1795
+ RG.parseObjectStyleConfig(this, conf.options);
1796
+ }
1797
+
1798
+
1799
+
1800
+
1801
+ /**
1802
+ * Grow
1803
+ *
1804
+ * The Bipolar chart Grow effect gradually increases the values of the bars
1805
+ *
1806
+ * @param object An object of options - eg: {frames: 30}
1807
+ * @param function A function to call when the effect is complete
1808
+ */
1809
+ this.grow = function ()
1810
+ {
1811
+ // Callback
1812
+ var opt = arguments[0] || {};
1813
+ var frames = opt.frames || 30;
1814
+ var frame = 0;
1815
+ var callback = arguments[1] || function () {};
1816
+ var obj = this;
1817
+
1818
+ // Save the data
1819
+ var originalLeft = RG.arrayClone(this.left);
1820
+ var originalRight = RG.arrayClone(this.right);
1821
+
1822
+
1823
+ // Stop the scale from changing by setting xmax (if it's not already set)
1824
+ if (RG.isNull(prop['chart.xmax'])) {
1825
+
1826
+ var xmax = 0;
1827
+
1828
+ // Go through the left and right data
1829
+ for (var i=0; i<this.left.length; i+=1) { xmax = ma.max(xmax, ma.abs(this.left[i])); }
1830
+ for (var i=0; i<this.right.length; i+=1) { xmax = ma.max(xmax, ma.abs(this.right[i])); }
1831
+
1832
+ var scale = RG.getScale2(obj, {'max':xmax});
1833
+ this.Set('chart.xmax', scale.max);
1834
+ }
1835
+
1836
+
1837
+
1838
+
1839
+
1840
+
1841
+
1842
+
1843
+
1844
+
1845
+
1846
+
1847
+ var iterator = function ()
1848
+ {
1849
+ var easingMultiplier = RG.Effects.getEasingMultiplier(frames, frame);
1850
+
1851
+ for (var i=0; i<obj.left.length; i+=1) { obj.left[i] = easingMultiplier * originalLeft[i]; }
1852
+ for (var i=0; i<obj.right.length; i+=1) { obj.right[i] = easingMultiplier * originalRight[i]; }
1853
+
1854
+ RG.redrawCanvas(obj.canvas);
1855
+
1856
+ // Repeat or call the end function if one is defined
1857
+ if (frame < frames) {
1858
+ frame += 1;
1859
+ RG.Effects.updateCanvas(iterator);
1860
+ } else {
1861
+ callback(obj);
1862
+ }
1863
+ };
1864
+
1865
+ iterator();
1866
+
1867
+ return this;
1868
+ };
1869
+
1870
+
1871
+
1872
+
1873
+ /**
1874
+ * Bipolar chart Wave effect.
1875
+ *
1876
+ * @param object OPTIONAL An object map of options. You specify 'frames' here to give the number of frames in the effect
1877
+ * @param function OPTIONAL A function that will be called when the effect is complete
1878
+ */
1879
+ this.wave = function ()
1880
+ {
1881
+ var obj = this,
1882
+ opt = arguments[0] || {};
1883
+ opt.frames = opt.frames || 60;
1884
+ opt.startFrames_left = [];
1885
+ opt.startFrames_right = [];
1886
+ opt.counters_left = [];
1887
+ opt.counters_right = [];
1888
+
1889
+ var framesperbar = opt.frames / 3,
1890
+ frame_left = -1,
1891
+ frame_right = -1,
1892
+ callback = arguments[1] || function () {},
1893
+ original_left = RG.arrayClone(obj.left),
1894
+ original_right = RG.arrayClone(obj.right);
1895
+
1896
+ for (var i=0,len=obj.left.length; i<len; i+=1) {
1897
+ opt.startFrames_left[i] = ((opt.frames / 2) / (obj.left.length - 1)) * i;
1898
+ opt.startFrames_right[i] = ((opt.frames / 2) / (obj.right.length - 1)) * i;
1899
+ opt.counters_left[i] = 0;
1900
+ opt.counters_right[i] = 0;
1901
+ }
1902
+
1903
+ // This stops the chart from jumping
1904
+ obj.draw();
1905
+ obj.set('xmax', obj.scale2.max);
1906
+ RG.clear(obj.canvas);
1907
+
1908
+
1909
+ // Zero all of the data
1910
+ for (var i=0,len=obj.left.length; i<len; i+=1) {
1911
+ if (typeof obj.left[i] === 'number') obj.left[i] = 0;
1912
+ if (typeof obj.right[i] === 'number') obj.right[i] = 0;
1913
+ }
1914
+
1915
+ //
1916
+ // Iterate over the left side
1917
+ //
1918
+ function iteratorLeft ()
1919
+ {
1920
+ ++frame_left;
1921
+
1922
+ for (var i=0,len=obj.left.length; i<len; i+=1) {
1923
+ if (frame_left > opt.startFrames_left[i]) {
1924
+
1925
+ var isNull = RG.isNull(obj.left[i]);
1926
+
1927
+ obj.left[i] = ma.min(
1928
+ ma.abs(original_left[i]),
1929
+ ma.abs(original_left[i] * ( (opt.counters_left[i]++) / framesperbar))
1930
+ );
1931
+
1932
+ // Make the number negative if the original was
1933
+ if (original_left[i] < 0) {
1934
+ obj.left[i] *= -1;
1935
+ }
1936
+
1937
+ if (isNull) {
1938
+ obj.left[i] = null;
1939
+ }
1940
+ } else {
1941
+ obj.left[i] = typeof obj.left[i] === 'object' && obj.left[i] ? RG.arrayPad([], obj.left[i].length, 0) : (RG.isNull(obj.left[i]) ? null : 0);
1942
+ }
1943
+
1944
+ }
1945
+
1946
+
1947
+ // No callback here - only called by the right function
1948
+ if (frame_left < opt.frames) {
1949
+ RG.redrawCanvas(obj.canvas);
1950
+ RG.Effects.updateCanvas(iteratorLeft);
1951
+ }
1952
+ }
1953
+
1954
+
1955
+
1956
+
1957
+ //
1958
+ // Iterate over the right side
1959
+ //
1960
+ function iteratorRight ()
1961
+ {
1962
+ ++frame_right;
1963
+
1964
+ for (var i=0,len=obj.right.length; i<len; i+=1) {
1965
+ if (frame_right > opt.startFrames_right[i]) {
1966
+
1967
+ var isNull = RG.isNull(obj.right[i]);
1968
+
1969
+ obj.right[i] = ma.min(
1970
+ ma.abs(original_right[i]),
1971
+ ma.abs(original_right[i] * ( (opt.counters_right[i]++) / framesperbar))
1972
+ );
1973
+
1974
+ // Make the number negative if the original was
1975
+ if (original_right[i] < 0) {
1976
+ obj.right[i] *= -1;
1977
+ }
1978
+
1979
+ if (isNull) {
1980
+ obj.right[i] = null;
1981
+ }
1982
+
1983
+ } else {
1984
+ obj.right[i] = typeof obj.right[i] === 'object' && obj.right[i] ? RG.arrayPad([], obj.right[i].length, 0) : (RG.isNull(obj.right[i]) ? null : 0);
1985
+ }
1986
+ }
1987
+
1988
+
1989
+ // No callback here - only called by the right function
1990
+ if (frame_right < opt.frames) {
1991
+ RG.redrawCanvas(obj.canvas);
1992
+ RG.Effects.updateCanvas(iteratorRight);
1993
+ } else {
1994
+ callback(this);
1995
+ }
1996
+ }
1997
+
1998
+
1999
+
2000
+
2001
+ iteratorLeft();
2002
+ iteratorRight();
2003
+
2004
+ return this;
2005
+ };
2006
+ };