rgraph-rails 5.00 → 6.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/publish-geml.yaml +46 -0
  3. data/.gitignore +1 -0
  4. data/README.md +4 -5
  5. data/lib/rgraph-rails/version.rb +1 -1
  6. data/rgraph-rails.gemspec +4 -4
  7. data/vendor/assets/javascripts/RGraph.activity.js +1691 -0
  8. data/vendor/assets/javascripts/RGraph.bar.js +4253 -236
  9. data/vendor/assets/javascripts/RGraph.bipolar.js +3958 -162
  10. data/vendor/assets/javascripts/RGraph.common.annotate.js +414 -35
  11. data/vendor/assets/javascripts/RGraph.common.context.js +635 -30
  12. data/vendor/assets/javascripts/RGraph.common.core.js +10485 -419
  13. data/vendor/assets/javascripts/RGraph.common.csv.js +508 -27
  14. data/vendor/assets/javascripts/RGraph.common.dynamic.js +1693 -90
  15. data/vendor/assets/javascripts/RGraph.common.effects.js +1629 -89
  16. data/vendor/assets/javascripts/RGraph.common.key.js +1003 -53
  17. data/vendor/assets/javascripts/RGraph.common.moment.js +5670 -0
  18. data/vendor/assets/javascripts/RGraph.common.sheets.js +541 -31
  19. data/vendor/assets/javascripts/RGraph.common.sheets.php +351 -0
  20. data/vendor/assets/javascripts/RGraph.common.starburst.js +382 -0
  21. data/vendor/assets/javascripts/RGraph.common.table.js +386 -0
  22. data/vendor/assets/javascripts/RGraph.common.tooltips.js +1433 -32
  23. data/vendor/assets/javascripts/RGraph.drawing.background.js +660 -35
  24. data/vendor/assets/javascripts/RGraph.drawing.circle.js +618 -34
  25. data/vendor/assets/javascripts/RGraph.drawing.image.js +857 -52
  26. data/vendor/assets/javascripts/RGraph.drawing.line.js +712 -0
  27. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +760 -38
  28. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +740 -37
  29. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +573 -36
  30. data/vendor/assets/javascripts/RGraph.drawing.poly.js +667 -36
  31. data/vendor/assets/javascripts/RGraph.drawing.rect.js +638 -34
  32. data/vendor/assets/javascripts/RGraph.drawing.text.js +672 -37
  33. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +653 -52
  34. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +714 -51
  35. data/vendor/assets/javascripts/RGraph.fuel.js +1149 -59
  36. data/vendor/assets/javascripts/RGraph.funnel.js +1277 -56
  37. data/vendor/assets/javascripts/RGraph.gantt.js +1646 -82
  38. data/vendor/assets/javascripts/RGraph.gauge.js +1773 -89
  39. data/vendor/assets/javascripts/RGraph.hbar.js +3869 -159
  40. data/vendor/assets/javascripts/RGraph.horseshoe.js +970 -0
  41. data/vendor/assets/javascripts/RGraph.hprogress.js +1829 -81
  42. data/vendor/assets/javascripts/RGraph.line.js +5293 -244
  43. data/vendor/assets/javascripts/RGraph.meter.js +1570 -77
  44. data/vendor/assets/javascripts/RGraph.modaldialog.js +300 -19
  45. data/vendor/assets/javascripts/RGraph.odo.js +1553 -68
  46. data/vendor/assets/javascripts/RGraph.pie.js +3273 -129
  47. data/vendor/assets/javascripts/RGraph.radar.js +2333 -108
  48. data/vendor/assets/javascripts/RGraph.rose.js +2685 -114
  49. data/vendor/assets/javascripts/RGraph.rscatter.js +1920 -80
  50. data/vendor/assets/javascripts/RGraph.scatter.js +4215 -171
  51. data/vendor/assets/javascripts/RGraph.segmented.js +1006 -0
  52. data/vendor/assets/javascripts/RGraph.semicircularprogress.js +1980 -59
  53. data/vendor/assets/javascripts/RGraph.svg.activity.js +1696 -0
  54. data/vendor/assets/javascripts/RGraph.svg.bar.js +2575 -77
  55. data/vendor/assets/javascripts/RGraph.svg.bipolar.js +3533 -106
  56. data/vendor/assets/javascripts/RGraph.svg.common.ajax.js +240 -21
  57. data/vendor/assets/javascripts/RGraph.svg.common.core.js +7105 -299
  58. data/vendor/assets/javascripts/RGraph.svg.common.csv.js +408 -28
  59. data/vendor/assets/javascripts/RGraph.svg.common.fx.js +1291 -68
  60. data/vendor/assets/javascripts/RGraph.svg.common.key.js +451 -20
  61. data/vendor/assets/javascripts/RGraph.svg.common.sheets.js +543 -31
  62. data/vendor/assets/javascripts/RGraph.svg.common.table.js +391 -0
  63. data/vendor/assets/javascripts/RGraph.svg.common.tooltips.js +1072 -23
  64. data/vendor/assets/javascripts/RGraph.svg.funnel.js +1151 -32
  65. data/vendor/assets/javascripts/RGraph.svg.gauge.js +1429 -34
  66. data/vendor/assets/javascripts/RGraph.svg.hbar.js +2692 -65
  67. data/vendor/assets/javascripts/RGraph.svg.horseshoe.js +969 -0
  68. data/vendor/assets/javascripts/RGraph.svg.line.js +2855 -86
  69. data/vendor/assets/javascripts/RGraph.svg.pie.js +1630 -58
  70. data/vendor/assets/javascripts/RGraph.svg.radar.js +1772 -58
  71. data/vendor/assets/javascripts/RGraph.svg.rose.js +2419 -83
  72. data/vendor/assets/javascripts/RGraph.svg.scatter.js +2280 -65
  73. data/vendor/assets/javascripts/RGraph.svg.segmented.js +930 -0
  74. data/vendor/assets/javascripts/RGraph.svg.semicircularprogress.js +1612 -29
  75. data/vendor/assets/javascripts/RGraph.svg.waterfall.js +1525 -50
  76. data/vendor/assets/javascripts/RGraph.thermometer.js +1411 -64
  77. data/vendor/assets/javascripts/RGraph.vprogress.js +1915 -81
  78. data/vendor/assets/javascripts/RGraph.waterfall.js +1896 -89
  79. data/vendor/assets/javascripts/financial-data.js +1067 -0
  80. metadata +37 -16
  81. data/.travis.yml +0 -11
  82. data/vendor/assets/javascripts/RGraph.common.deprecated.js +0 -35
  83. data/vendor/assets/javascripts/RGraph.common.resizing.js +0 -38
  84. data/vendor/assets/javascripts/RGraph.common.zoom.js +0 -15
  85. data/vendor/assets/javascripts/RGraph.cornergauge.js +0 -71
@@ -1,66 +1,2281 @@
1
+ 'version:2023-09-16 (6.14)';
2
+ //
3
+ // o--------------------------------------------------------------------------------o
4
+ // | This file is part of the RGraph package - you can learn more at: |
5
+ // | |
6
+ // | https://www.rgraph.net |
7
+ // | |
8
+ // | RGraph is licensed under the Open Source MIT license. That means that it's |
9
+ // | totally free to use and there are no restrictions on what you can do with it! |
10
+ // o--------------------------------------------------------------------------------o
1
11
 
2
- RGraph=window.RGraph||{isRGraph:true};RGraph.SVG=RGraph.SVG||{};(function(win,doc,undefined)
3
- {var RG=RGraph,ua=navigator.userAgent,ma=Math,win=window,doc=document;RG.SVG.Scatter=function(conf)
4
- {this.set=function(name,value)
5
- {if(arguments.length===1&&typeof name==='object'){for(i in arguments[0]){if(typeof i==='string'){name=ret.name;value=ret.value;this.set(name,value);}}}else{var ret=RG.SVG.commonSetter({object:this,name:name,value:value});name=ret.name;value=ret.value;this.properties[name]=value;if(name==='colors'){this.originalColors=RG.SVG.arrayClone(value);this.colorsParsed=false;}}
6
- return this;};this.get=function(name)
7
- {return this.properties[name];};this.id=conf.id;this.uid=RG.SVG.createUID();this.container=document.getElementById(this.id);this.layers={};this.svg=RG.SVG.createSVG({object:this,container:this.container});this.isRGraph=true;this.width=Number(this.svg.getAttribute('width'));this.height=Number(this.svg.getAttribute('height'));this.data=conf.data;this.type='scatter';this.coords=[];this.coords2=[];this.colorsParsed=false;this.originalColors={};this.gradientCounter=1;this.sequential=0;this.line_groups=[];this.propertyNameAliases={};RG.SVG.OR.add(this);this.container.style.display='inline-block';this.properties={marginLeft:35,marginRight:35,marginTop:35,marginBottom:35,backgroundColor:null,backgroundImage:null,backgroundImageAspect:'none',backgroundImageStretch:true,backgroundImageOpacity:null,backgroundImageX:null,backgroundImageY:null,backgroundImageW:null,backgroundImageH:null,backgroundGrid:true,backgroundGridColor:'#ddd',backgroundGridLinewidth:1,backgroundGridHlines:true,backgroundGridHlinesCount:null,backgroundGridVlines:true,backgroundGridVlinesCount:null,backgroundGridBorder:true,backgroundGridDashed:false,backgroundGridDotted:false,backgroundGridDashArray:null,xmax:0,tickmarksStyle:'cross',tickmarksSize:7,colors:['black'],line:false,lineColors:1,lineLinewidth:1,errorbarsColor:'black',errorbarsLinewidth:1,errorbarsCapwidth:10,yaxis:true,yaxisTickmarks:true,yaxisTickmarksLength:3,yaxisColor:'black',yaxisScale:true,yaxisLabels:null,yaxisLabelsOffsetx:0,yaxisLabelsOffsety:0,yaxisLabelsCount:5,yaxisScaleUnitsPre:'',yaxisScaleUnitsPost:'',yaxisScaleStrict:false,yaxisScaleDecimals:0,yaxisScalePoint:'.',yaxisScaleThousand:',',yaxisScaleRound:false,yaxisScaleMax:null,yaxisScaleMin:0,yaxisScaleFormatter:null,xaxis:true,xaxisTickmarks:true,xaxisTickmarksLength:5,xaxisLabels:null,xaxisLabelsPosition:'section',xaxisLabelsPositionEdgeTickmarksCount:10,xaxisColor:'black',xaxisLabelsOffsetx:0,xaxisLabelsOffsety:0,xaxisLabelsCount:10,xaxisLabelsFont:null,xaxisLabelsSize:null,xaxisLabelsColor:null,xaxisLabelsBold:null,xaxisLabelsItalic:null,xaxisScaleUnitsPre:'',xaxisScaleUnitsPost:'',xaxisScaleMax:null,xaxisScaleMin:0,xaxisScalePoint:'.',xaxisRound:false,xaxisScaleThousand:',',xaxisScaleDecimals:0,xaxisScaleFormatter:null,textColor:'black',textFont:'Arial, Verdana, sans-serif',textSize:12,textBold:false,textItalic:false,labelsAboveFont:null,labelsAboveSize:null,labelsAboveBold:null,labelsAboveItalic:null,labelsAboveColor:null,labelsAboveBackground:'rgba(255,255,255,0.7)',labelsAboveBackgroundPadding:2,labelsAboveXUnitsPre:null,labelsAboveXUnitsPost:null,labelsAboveXPoint:null,labelsAboveXThousand:null,labelsAboveXFormatter:null,labelsAboveXDecimals:null,labelsAboveYUnitsPre:null,labelsAboveYUnitsPost:null,labelsAboveYPoint:null,labelsAboveYThousand:null,labelsAboveYFormatter:null,labelsAboveYDecimals:null,labelsAboveOffsetx:0,labelsAboveOffsety:-10,labelsAboveHalign:'center',labelsAboveValign:'bottom',labelsAboveSeperator:',',tooltipsOverride:null,tooltipsEffect:'fade',tooltipsCssClass:'RGraph_tooltip',tooltipsEvent:'mousemove',highlightStroke:'rgba(0,0,0,0)',highlightFill:'rgba(255,255,255,0.7)',highlightLinewidth:1,title:'',titleX:null,titleY:null,titleHalign:'center',titleValign:null,titleSize:null,titleColor:null,titleFont:null,titleBold:null,titleItalic:null,titleSubtitle:null,titleSubtitleX:null,titleSubtitleY:null,titleSubtitleHalign:'center',titleSubtitleValign:null,titleSubtitleSize:null,titleSubtitleColor:'#aaa',titleSubtitleFont:null,titleSubtitleBold:null,titleSubtitleItalic:null,key:null,keyColors:null,keyOffsetx:0,keyOffsety:0,keyLabelsOffsetx:0,keyLabelsOffsety:-1,keyLabelsFont:null,keyLabelsSize:null,keyLabelsColor:null,keyLabelsBold:null,keyLabelsItalic:null,bubble:false,bubbleMaxValue:null,bubbleMaxRadius:null,bubbleColorsSolid:false,errorbars:null,errorbarsColor:'black',errorbarsLinewidth:1,errorbarsCapwidth:10,};RG.SVG.getGlobals(this);for(i in conf.options){if(typeof i==='string'){this.set(i,conf.options[i]);}}
8
- if(this.data[0]&&!RG.SVG.isArray(this.data[0])){this.data=[];this.data[0]=conf.data;}
9
- if(RG.SVG.FX&&typeof RG.SVG.FX.decorate==='function'){RG.SVG.FX.decorate(this);}
10
- var prop=this.properties;if(typeof prop.xaxisScaleMin==='string'){prop.xaxisScaleMin=RG.SVG.parseDate(prop.xaxisScaleMin);}
11
- if(typeof prop.xaxisScaleMax==='string'){prop.xaxisScaleMax=RG.SVG.parseDate(prop.xaxisScaleMax);}
12
- for(var i=0;i<this.data.length;++i){for(var j=0;j<this.data[i].length;++j){if(typeof this.data[i][j].x==='string'){this.data[i][j].x=RG.SVG.parseDate(this.data[i][j].x);}}}
13
- this.draw=function()
14
- {RG.SVG.fireCustomEvent(this,'onbeforedraw');this.width=Number(this.svg.getAttribute('width'));this.height=Number(this.svg.getAttribute('height'));RG.SVG.createDefs(this);this.graphWidth=this.width-prop.marginLeft-prop.marginRight;this.graphHeight=this.height-prop.marginTop-prop.marginBottom;this.coords=[];this.coords2=[];RG.SVG.resetColorsToOriginalValues({object:this});this.parseColors();for(var ds=0,max=0;ds<this.data.length;++ds){for(var dp=0;dp<this.data[ds].length;++dp){max=ma.max(max,this.data[ds][dp].y+(this.data[ds][dp].errorbar?(typeof this.data[ds][dp].errorbar==='number'?this.data[ds][dp].errorbar:this.data[ds][dp].errorbar.max):0));}}
15
- if(typeof prop.yaxisScaleMax==='number'){max=prop.yaxisScaleMax;}
16
- if(prop.yaxisScaleMin==='mirror'||prop.yaxisScaleMin==='middle'||prop.yaxisScaleMin==='center'){var mirrorScale=true;prop.yaxisScaleMin=0;}
17
- this.scale=RG.SVG.getScale({object:this,numlabels:prop.yaxisLabelsCount,unitsPre:prop.yaxisScaleUnitsPre,unitsPost:prop.yaxisScaleUnitsPost,max:max,min:prop.yaxisScaleMin,point:prop.yaxisScalePoint,round:prop.yaxisScaleRound,thousand:prop.yaxisScaleThousand,decimals:prop.yaxisScaleDecimals,strict:typeof prop.yaxisScaleMax==='number',formatter:prop.yaxisScaleFormatter});if(mirrorScale){this.scale=RG.SVG.getScale({object:this,numlabels:prop.yaxisLabelsCount,unitsPre:prop.yaxisScaleUnitsPre,unitsPost:prop.yaxisScaleUnitsPost,max:this.scale.max,min:this.scale.max* -1,point:prop.yaxisScalePoint,round:false,thousand:prop.yaxisScaleThousand,decimals:prop.yaxisScaleDecimals,strict:typeof prop.yaxisScaleMax==='number',formatter:prop.yaxisScaleFormatter});}
18
- this.max=this.scale.max;this.min=this.scale.min;prop.yaxisScaleMax=this.scale.max;prop.yaxisScaleMin=this.scale.min;RG.SVG.drawBackground(this);RG.SVG.drawXAxis(this);RG.SVG.drawYAxis(this);var dataset_group=RGraph.SVG.create({svg:this.svg,type:'g',parent:this.svg.all,attr:{className:'scatter_datasets_'+this.uid}});for(var i=0;i<this.data.length;++i){var group=RG.SVG.create({svg:this.svg,type:'g',parent:this.svg.all,attr:{id:'scatter_line_'+i+this.uid}});this.line_groups[i]=group;this.drawPoints({index:i,data:this.data[i],group:dataset_group});if(prop.line===true||(typeof prop.line==='object'&&prop.line[i]===true)){this.drawLine({index:i,coords:this.coords2[i],});}}
19
- if(typeof prop.key!==null&&RG.SVG.drawKey){RG.SVG.drawKey(this);}else if(!RGraph.SVG.isNull(prop.key)){alert('The drawKey() function does not exist - have you forgotten to include the key library?');}
20
- RG.SVG.fireCustomEvent(this,'ondraw');return this;};this.drawPoints=function(opt)
21
- {var index=opt.index,data=opt.data,group=opt.group;if(!this.coords2[index]){this.coords2[index]=[];}
22
- var group=RG.SVG.create({svg:this.svg,type:'g',parent:group,attr:{className:'scatter_dataset_'+index+'_'+this.uid}});for(var i=0;i<data.length;++i){var point=data[i];if(typeof point.x==='number'&&typeof point.y==='number'){var ret=this.drawSinglePoint({dataset:data,datasetIdx:index,point:point,index:i,group:group,sequential:this.sequential});this.coords.push({x:ret.x,y:ret.y,z:ret.size,type:ret.type,element:ret.mark,object:this});this.coords2[index][i]={x:ret.x,y:ret.y,z:ret.size,type:ret.type,element:ret.mark,object:this};this.sequential++}
23
- if((typeof data[i].tooltip==='string'&&data[i].tooltip)||(typeof data[i].tooltip==='number')){data[i].tooltip=String(data[i].tooltip);if(prop.tooltipsEvent!=='mousemove'){prop.tooltipsEvent='click';}
24
- if(!group_tooltip_hotspots){var group_tooltip_hotspots=RG.SVG.create({svg:this.svg,parent:this.svg.all,type:'g',attr:{className:'rgraph-scatter-tooltip-hotspots'}});}
25
- var rect=RG.SVG.create({svg:this.svg,parent:this.svg.all,type:'rect',parent:group_tooltip_hotspots,attr:{x:ret.x-(ret.size/2),y:ret.y-(ret.size/2),width:ret.size,height:ret.size,fill:'transparent',stroke:'transparent','stroke-width':0},style:{cursor:'pointer'}});ret.mark.hotspot=rect;(function(dataset,index,seq,obj)
26
- {rect.addEventListener(prop.tooltipsEvent,function(e)
27
- {var tooltip=RG.SVG.REG.get('tooltip');if(tooltip&&tooltip.__dataset__===dataset&&tooltip.__index__===index){return;}
28
- obj.removeHighlight();RG.SVG.tooltip({object:obj,dataset:dataset,index:index,sequentialIndex:seq,text:obj.data[dataset][index].tooltip,event:e});if(RG.SVG.REG.get('tooltip')){obj.highlight(this);}},false);if(prop.tooltipsEvent==='click'){rect.addEventListener('mousemove',function(e)
29
- {e.target.style.cursor='pointer';},false);}}(index,i,this.sequential-1,this));}}};this.drawSinglePoint=function(opt)
30
- {var dataset=opt.dataset,datasetIdx=opt.datasetIdx,seq=opt.sequential,point=opt.point,index=opt.index,valueX=opt.point.x,valueY=opt.point.y,conf=opt.point||{},group=opt.group,coordX=opt.coordx=this.getXCoord(valueX),coordY=opt.coordy=this.getYCoord(valueY);if(conf.labelsAbove){var above=true;}else if(conf.labelAbove){var above=true;}else if(conf.above){var above=true;}
31
- if(typeof conf.type==='undefined'&&typeof conf.shape!=='undefined'){conf.type=conf.shape;}
32
- if(typeof conf.type==='string'){}else if(typeof prop.tickmarksStyle==='string'){conf.type=prop.tickmarksStyle;}else if(typeof prop.tickmarksStyle==='object'&&typeof prop.tickmarksStyle[datasetIdx]==='string'){conf.type=prop.tickmarksStyle[datasetIdx];}
33
- if(typeof conf.size!=='number'&&typeof prop.tickmarksSize==='number'){conf.size=prop.tickmarksSize;}else if(typeof conf.size!=='number'&&typeof prop.tickmarksSize==='object'&&typeof prop.tickmarksSize[datasetIdx]==='number'){conf.size=prop.tickmarksSize[datasetIdx];}
34
- if(typeof conf.color==='string'){}else if(typeof prop.colors[datasetIdx]==='string'){conf.color=prop.colors[datasetIdx];}else{conf.color='black';}
35
- if(typeof conf.opacity==='undefined'){conf.opacity=1;}else if(typeof conf.opacity==='number'){}
36
- prop.errorbars=[];for(var ds=0,max=0;ds<this.data.length;++ds){for(var idx=0;idx<this.data[ds].length;++idx){prop.errorbars.push(this.data[ds][idx].errorbar);}}
37
- this.drawErrorbar({object:this,dataset:datasetIdx,index:index,group:group,sequential:seq,x:coordX,y:coordY,valueX:valueX,valueY:valueY,parent:group});if(prop.bubble){this.drawBubble(opt,conf);}
38
- switch(conf.type){case'image:'+conf.type.substr(6):var src=conf.type.substr(6);var img=new Image();img.src=src;var mark=RG.SVG.create({svg:this.svg,type:'image',parent:group,attr:{preserveAspectRatio:'xMidYMid meet','xlink:href':src}});img.onload=function()
39
- {var x=coordX-(img.width/2),y=coordY-(img.height/2),w=img.width,h=img.height;mark.setAttribute('x',x);mark.setAttribute('y',y);mark.setAttribute('width',w);mark.setAttribute('height',h);if(mark&&mark.hotspot){mark.hotspot.setAttribute('x',x);mark.hotspot.setAttribute('y',y);mark.hotspot.setAttribute('width',w);mark.hotspot.setAttribute('height',h);}};break;case'triangle':var mark=RG.SVG.create({svg:this.svg,type:'path',parent:group,attr:{d:'M {1} {2} L {3} {4} L {5} {6}'.format(coordX-(conf.size/2),coordY+(conf.size/2),coordX,coordY-(conf.size/2),coordX+(conf.size/2),coordY+(conf.size/2)),fill:conf.color,'fill-opacity':conf.opacity}});break;case'plus':var mark=RG.SVG.create({svg:this.svg,type:'path',parent:group,attr:{d:'M {1} {2} L {3} {4} M {5} {6} L {7} {8}'.format(coordX-(conf.size/2),coordY,coordX+(conf.size/2),coordY,coordX,coordY-(conf.size/2),coordX,coordY+(conf.size/2)),stroke:conf.color,'stroke-opacity':conf.opacity}});break;case'square':case'rect':var mark=RG.SVG.create({svg:this.svg,type:'rect',parent:group,attr:{x:coordX-(conf.size/2),y:coordY-(conf.size/2),width:conf.size,height:conf.size,fill:conf.color,'fill-opacity':conf.opacity}});break;case'dot':case'circle':var mark=RG.SVG.create({svg:this.svg,type:'circle',parent:group,attr:{cx:coordX,cy:coordY,r:conf.size/2,fill:conf.color,'fill-opacity':conf.opacity}});break;case'cross':default:var mark=RG.SVG.create({svg:this.svg,type:'path',parent:group,attr:{d:'M {1} {2} L {3} {4} M {5} {6} L {7} {8}'.format(coordX-(conf.size/2),coordY-(conf.size/2),coordX+(conf.size/2),coordY+(conf.size/2),coordX-(conf.size/2),coordY+(conf.size/2),coordX+(conf.size/2),coordY-(conf.size/2)),stroke:conf.color,'stroke-opacity':conf.opacity}});break;}
40
- if(typeof conf.above==='string'||(typeof conf.above!=='string'&&conf.above)){this.drawLabelsAbove({point:conf,coordX:coordX,coordY:coordY});}
41
- mark.setAttribute('data-index',index);mark.setAttribute('data-dataset',datasetIdx);mark.setAttribute('data-original-opacity',conf.opacity);mark.setAttribute('data-original-color',conf.color);mark.setAttribute('data-original-coordx',coordX);mark.setAttribute('data-original-coordy',coordY);mark.setAttribute('data-size',conf.size);mark.setAttribute('data-sequential',seq);mark.setAttribute('data-type',conf.type);return{x:coordX,y:coordY,size:conf.type.substr(0,6)==='image:'?img.width:conf.size,mark:mark,type:conf.type};};this.drawBubble=function(opt,conf)
42
- {var size=(conf.z/prop.bubbleMaxValue)*prop.bubbleMaxRadius;var color=RG.SVG.parseColorRadial({object:this,color:prop.bubbleColorsSolid?conf.color:'Gradient(white:'+conf.color+')',cx:opt.coordx+(size/4),cy:opt.coordy-(size/4),fx:opt.coordx+(size/4),fy:opt.coordy-(size/4),r:size*1.5});var circle=RG.SVG.create({svg:this.svg,type:'circle',attr:{cx:opt.coordx,cy:opt.coordy,r:size,fill:color,'fill-opacity':conf.opacity}});circle.setAttribute('data-index',opt.index);circle.setAttribute('data-dataset',opt.datasetIdx);circle.setAttribute('data-original-opacity',conf.opacity);circle.setAttribute('data-original-color',conf.color);circle.setAttribute('data-original-coordx',opt.coordx);circle.setAttribute('data-original-coordy',opt.coordy);circle.setAttribute('data-size',size);circle.setAttribute('data-sequential',opt.sequential);circle.setAttribute('data-type','bubble');return{x:opt.coordx,y:opt.coordy,z:opt.coordz};};this.drawLine=function(opt)
43
- {var linewidth=1,color='black';if(typeof prop.lineLinewidth==='object'&&typeof prop.lineLinewidth[opt.index]==='number'){linewidth=prop.lineLinewidth[opt.index];}else if(typeof prop.lineLinewidth==='number'){linewidth=prop.lineLinewidth;}else{linewidth=1;}
44
- if(typeof prop.lineColors==='object'&&prop.lineColors[opt.index]){color=prop.lineColors[opt.index];}else if(prop.colors[opt.index]==='string'){color=prop.colors[opt.index];}else{color='black';}
45
- for(var i=0,path='';i<this.coords2[opt.index].length;++i){path+='{1} {2} {3} '.format(i===0?'M':'L',this.coords2[opt.index][i].x,this.coords2[opt.index][i].y);}
46
- RG.SVG.create({svg:this.svg,type:'path',parent:this.line_groups[opt.index],attr:{d:path,fill:'transparent',stroke:color,'stroke-width':linewidth,'stroke-linecap':'round','stroke-linejoin':'round'}});};this.getXCoord=function(value)
47
- {var x;if(value>prop.xaxisScaleMax){return null;}
48
- if(value<prop.xaxisScaleMin){return null;}
49
- x=((value-prop.xaxisScaleMin)/(prop.xaxisScaleMax-prop.xaxisScaleMin));x*=(this.width-prop.marginLeft-prop.marginRight);x=prop.marginLeft+x;return x;};this.getYCoord=function(value)
50
- {var prop=this.properties;if(value>this.scale.max){return null;}
51
- var y,xaxispos=prop.xaxispos;if(value<this.scale.min){return null;}
52
- y=((value-this.scale.min)/(this.scale.max-this.scale.min));y*=(this.height-prop.marginTop-prop.marginBottom);y=this.height-prop.marginBottom-y;return y;};this.highlight=function(rect)
53
- {rect.setAttribute('fill',prop.highlightFill);RG.SVG.REG.set('highlight',rect);};this.drawLabelsAbove=function(opt)
54
- {var conf=opt.point,coordX=opt.coordX,coordY=opt.coordY;if(typeof conf.above==='string'){var str=conf.above;}else{conf.x=RG.SVG.numberFormat({object:this,num:conf.x.toFixed(prop.labelsAboveXDecimals),prepend:typeof prop.labelsAboveXUnitsPre==='string'?prop.labelsAboveXUnitsPre:null,append:typeof prop.labelsAboveXUnitsPost==='string'?prop.labelsAboveXUnitsPost:null,point:typeof prop.labelsAboveXPoint==='string'?prop.labelsAboveXPoint:null,thousand:typeof prop.labelsAboveXThousand==='string'?prop.labelsAboveXThousand:null,formatter:typeof prop.labelsAboveXFormatter==='function'?prop.labelsAboveXFormatter:null});conf.y=RG.SVG.numberFormat({object:this,num:conf.y.toFixed(prop.labelsAboveYDecimals),prepend:typeof prop.labelsAboveYUnitsPre==='string'?prop.labelsAboveYUnitsPre:null,append:typeof prop.labelsAboveYUnitsPost==='string'?prop.labelsAboveYUnitsPost:null,point:typeof prop.labelsAboveYPoint==='string'?prop.labelsAboveYPoint:null,thousand:typeof prop.labelsAboveYThousand==='string'?prop.labelsAboveYThousand:null,formatter:typeof prop.labelsAboveYFormatter==='function'?prop.labelsAboveYFormatter:null});var str='{1}{2}{3}'.format(conf.x,prop.labelsAboveSeperator,conf.y);}
55
- RG.SVG.text({object:this,parent:this.svg.all,tag:'labels.above',text:str,x:parseFloat(coordX)+prop.labelsAboveOffsetx,y:parseFloat(coordY)+prop.labelsAboveOffsety,halign:prop.labelsAboveHalign,valign:prop.labelsAboveValign,font:prop.labelsAboveFont||prop.textFont,size:typeof prop.labelsAboveSize==='number'?prop.labelsAboveSize:prop.textSize,bold:typeof prop.labelsAboveBold==='boolean'?prop.labelsAboveBold:prop.textBold,italic:typeof prop.labelsAboveItalic==='boolean'?prop.labelsAboveItalic:prop.textItalic,color:prop.labelsAboveColor||prop.textColor,background:prop.labelsAboveBackground||null,padding:prop.labelsAboveBackgroundPadding||0});};this.parseColors=function()
56
- {if(!Object.keys(this.originalColors).length){this.originalColors={colors:RG.SVG.arrayClone(prop.colors),backgroundGridColor:RG.SVG.arrayClone(prop.backgroundGridColor),highlightFill:RG.SVG.arrayClone(prop.highlightFill),backgroundColor:RG.SVG.arrayClone(prop.backgroundColor)}}
57
- var colors=prop.colors;if(colors&&!prop.bubble){for(var i=0;i<colors.length;++i){colors[i]=RG.SVG.parseColorLinear({object:this,color:colors[i]});}}
58
- prop.backgroundGridColor=RG.SVG.parseColorLinear({object:this,color:prop.backgroundGridColor});prop.highlightFill=RG.SVG.parseColorLinear({object:this,color:prop.highlightFill});prop.backgroundColor=RG.SVG.parseColorLinear({object:this,color:prop.backgroundColor});};this.on=function(type,func)
59
- {if(type.substr(0,2)!=='on'){type='on'+type;}
60
- RG.SVG.addCustomEventListener(this,type,func);return this;};this.exec=function(func)
61
- {func(this);return this;};this.removeHighlight=function()
62
- {var highlight=RG.SVG.REG.get('highlight');if(highlight){highlight.setAttribute('fill','transparent');RG.SVG.REG.set('highlight',null);}};this.drawErrorbar=function(opt)
63
- {var max=RG.SVG.getErrorbarsMaxValue({object:this,index:opt.sequential});var min=RG.SVG.getErrorbarsMinValue({object:this,index:opt.sequential});if(!max&&!min){return;}
64
- var linewidth=RG.SVG.getErrorbarsLinewidth({object:this,index:opt.sequential}),color=RG.SVG.getErrorbarsColor({object:this,index:opt.sequential}),capwidth=RG.SVG.getErrorbarsCapWidth({object:this,index:opt.sequential}),halfCapWidth=capwidth/2;if(max!==0||min!==0){var y1=this.getYCoord(opt.valueY+max)
65
- y2=this.getYCoord(opt.valueY-min);var errorbarLine=RG.SVG.create({svg:this.svg,type:'line',parent:opt.parent,attr:{x1:opt.x,y1:opt.y,x2:opt.x,y2:y1,stroke:color,'stroke-width':linewidth}});var errorbarCap=RG.SVG.create({svg:this.svg,type:'line',parent:opt.parent,attr:{x1:opt.x-halfCapWidth,y1:y1,x2:opt.x+halfCapWidth,y2:y1,stroke:color,'stroke-width':linewidth}});}
66
- if(typeof min==='number'){var errorbarLine=RG.SVG.create({svg:this.svg,type:'line',parent:opt.parent,attr:{x1:opt.x,y1:opt.y,x2:opt.x,y2:y2,stroke:color,'stroke-width':linewidth}});var errorbarCap=RG.SVG.create({svg:this.svg,type:'line',parent:opt.parent,attr:{x1:opt.x-halfCapWidth,y1:y2,x2:opt.x+halfCapWidth,y2:y2,stroke:color,'stroke-width':linewidth}});}};};return this;})(window,document);
12
+ RGraph = window.RGraph || {isrgraph:true,isRGraph:true,rgraph:true};
13
+ RGraph.SVG = RGraph.SVG || {};
14
+
15
+ // Module pattern
16
+ (function (win, doc, undefined)
17
+ {
18
+ RGraph.SVG.Scatter = function (conf)
19
+ {
20
+ //
21
+ // A setter that the constructor uses (at the end)
22
+ // to set all of the properties
23
+ //
24
+ // @param string name The name of the property to set
25
+ // @param string value The value to set the property to
26
+ //
27
+ this.set = function (name, value)
28
+ {
29
+ if (arguments.length === 1 && typeof name === 'object') {
30
+ for (i in arguments[0]) {
31
+ if (typeof i === 'string') {
32
+
33
+ name = ret.name;
34
+ value = ret.value;
35
+
36
+ this.set(name, value);
37
+ }
38
+ }
39
+ } else {
40
+
41
+ var ret = RGraph.SVG.commonSetter({
42
+ object: this,
43
+ name: name,
44
+ value: value
45
+ });
46
+
47
+ name = ret.name;
48
+ value = ret.value;
49
+
50
+ // If setting the colors, update the originalColors
51
+ // property too
52
+ if (name === 'colors') {
53
+ this.originalColors = RGraph.SVG.arrayClone(value);
54
+ this.colorsParsed = false;
55
+ }
56
+
57
+ // BC for labelsAboveSeperator
58
+ if (name === 'labelsAboveSeperator') {
59
+ name = labelsAboveSeparator;
60
+ }
61
+
62
+ this.properties[name] = value;
63
+ }
64
+
65
+ return this;
66
+ };
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+ //
76
+ // A getter.
77
+ //
78
+ // @param name string The name of the property to get
79
+ //
80
+ this.get = function (name)
81
+ {
82
+ return this.properties[name];
83
+ };
84
+
85
+
86
+
87
+
88
+
89
+
90
+ this.id = conf.id;
91
+ this.uid = RGraph.SVG.createUID();
92
+ this.container = document.getElementById(this.id);
93
+ this.layers = {}; // MUST be before the SVG tag is created!
94
+ this.svg = RGraph.SVG.createSVG({object: this,container: this.container});
95
+ this.isRGraph = true;
96
+ this.isrgraph = true;
97
+ this.rgraph = true;
98
+ this.width = Number(this.svg.getAttribute('width'));
99
+ this.height = Number(this.svg.getAttribute('height'));
100
+ this.data = conf.data;
101
+ this.type = 'scatter';
102
+ this.coords = [];
103
+ this.coords2 = [];
104
+ this.colorsParsed = false;
105
+ this.originalColors = {};
106
+ this.gradientCounter = 1;
107
+ this.sequential = 0;
108
+ this.line_groups = [];
109
+ this.firstDraw = true; // After the first draw this will be false
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+ // Add this object to the ObjectRegistry
119
+ RGraph.SVG.OR.add(this);
120
+
121
+ this.container.style.display = 'inline-block';
122
+
123
+ this.properties =
124
+ {
125
+ marginLeft: 35,
126
+ marginRight: 35,
127
+ marginTop: 35,
128
+ marginBottom: 35,
129
+
130
+ backgroundColor: null,
131
+ backgroundImage: null,
132
+ backgroundImageAspect: 'none',
133
+ backgroundImageStretch: true,
134
+ backgroundImageOpacity: null,
135
+ backgroundImageX: null,
136
+ backgroundImageY: null,
137
+ backgroundImageW: null,
138
+ backgroundImageH: null,
139
+ backgroundGrid: true,
140
+ backgroundGridColor: '#ddd',
141
+ backgroundGridLinewidth: 1,
142
+ backgroundGridHlines: true,
143
+ backgroundGridHlinesCount: null,
144
+ backgroundGridVlines: true,
145
+ backgroundGridVlinesCount: null,
146
+ backgroundGridBorder: true,
147
+ backgroundGridDashed: false,
148
+ backgroundGridDotted: false,
149
+ backgroundGridDashArray: null,
150
+
151
+ tickmarksStyle: 'cross',
152
+ tickmarksSize: 7,
153
+ colors: ['black'],
154
+
155
+ line: false,
156
+ lineColors: null,
157
+ lineLinewidth: 1,
158
+
159
+ errorbarsColor: 'black',
160
+ errorbarsLinewidth: 1,
161
+ errorbarsCapwidth: 10,
162
+
163
+ yaxis: true,
164
+ yaxisTickmarks: true,
165
+ yaxisTickmarksLength: 3,
166
+ yaxisColor: 'black',
167
+ yaxisScale: true,
168
+ yaxisLabels: null,
169
+ yaxisLabelsOffsetx: 0,
170
+ yaxisLabelsOffsety: 0,
171
+ yaxisLabelsCount: 5,
172
+ yaxisScaleUnitsPre: '',
173
+ yaxisScaleUnitsPost: '',
174
+ yaxisScaleStrict: false,
175
+ yaxisScaleDecimals: 0,
176
+ yaxisScalePoint: '.',
177
+ yaxisScaleThousand: ',',
178
+ yaxisScaleRound: false,
179
+ yaxisScaleMax: null,
180
+ yaxisScaleMin: 0,
181
+ yaxisScaleFormatter: null,
182
+ yaxisTitle: '',
183
+ yaxisTitleBold: null,
184
+ yaxisTitleSize: null,
185
+ yaxisTitleFont: null,
186
+ yaxisTitleColor: null,
187
+ yaxisTitleItalic: null,
188
+ yaxisTitleOffsetx: 0,
189
+ yaxisTitleOffsety: 0,
190
+ yaxisTitleX: null,
191
+ yaxisTitleY: null,
192
+ yaxisTitleHalign: null,
193
+ yaxisTitleValign: null,
194
+
195
+ xaxis: true,
196
+ xaxisTickmarks: true,
197
+ xaxisTickmarksLength: 5,
198
+ xaxisLabels: null,
199
+ xaxisLabelsPosition: 'section',
200
+ xaxisLabelsPositionEdgeTickmarksCount: 10,
201
+ xaxisColor: 'black',
202
+ xaxisLabelsOffsetx: 0,
203
+ xaxisLabelsOffsety: 0,
204
+ xaxisLabelsCount: 10,
205
+ xaxisLabelsFont: null,
206
+ xaxisLabelsSize: null,
207
+ xaxisLabelsColor: null,
208
+ xaxisLabelsBold: null,
209
+ xaxisLabelsItalic: null,
210
+ xaxisScaleUnitsPre: '',
211
+ xaxisScaleUnitsPost: '',
212
+ xaxisScaleMax: null,
213
+ xaxisScaleMin: 0,
214
+ xaxisScalePoint: '.',
215
+ xaxisRound: false,
216
+ xaxisScaleThousand: ',',
217
+ xaxisScaleDecimals: 0,
218
+ xaxisScaleFormatter: null,
219
+ xaxisTitle: '',
220
+ xaxisTitleBold: null,
221
+ xaxisTitleSize: null,
222
+ xaxisTitleFont: null,
223
+ xaxisTitleColor: null,
224
+ xaxisTitleItalic: null,
225
+ xaxisTitleOffsetx: 0,
226
+ xaxisTitleOffsety: 0,
227
+ xaxisTitleX: null,
228
+ xaxisTitleY: null,
229
+ xaxisTitleHalign: null,
230
+ xaxisTitleValign: null,
231
+
232
+ textColor: 'black',
233
+ textFont: 'Arial, Verdana, sans-serif',
234
+ textSize: 12,
235
+ textBold: false,
236
+ textItalic: false,
237
+ text: null,
238
+
239
+
240
+ labelsAboveFont: null,
241
+ labelsAboveSize: null,
242
+ labelsAboveBold: null,
243
+ labelsAboveItalic: null,
244
+ labelsAboveColor: null,
245
+ labelsAboveBackground: 'rgba(255,255,255,0.7)',
246
+ labelsAboveBackgroundPadding: 2,
247
+ labelsAboveXUnitsPre: null,
248
+ labelsAboveXUnitsPost: null,
249
+ labelsAboveXPoint: null,
250
+ labelsAboveXThousand: null,
251
+ labelsAboveXFormatter: null,
252
+ labelsAboveXDecimals: null,
253
+ labelsAboveYUnitsPre: null,
254
+ labelsAboveYUnitsPost: null,
255
+ labelsAboveYPoint: null,
256
+ labelsAboveYThousand: null,
257
+ labelsAboveYFormatter: null,
258
+ labelsAboveYDecimals: null,
259
+ labelsAboveOffsetx: 0,
260
+ labelsAboveOffsety: -10,
261
+ labelsAboveHalign: 'center',
262
+ labelsAboveValign: 'bottom',
263
+ labelsAboveSeparator: ',',
264
+
265
+ tooltipsOverride: null,
266
+ tooltipsEffect: 'fade',
267
+ tooltipsCssClass: 'RGraph_tooltip',
268
+ tooltipsCss: null,
269
+ tooltipsEvent: 'mousemove',
270
+ tooltipsFormattedThousand: ',',
271
+ tooltipsFormattedPoint: '.',
272
+ tooltipsFormattedDecimals: 0,
273
+ tooltipsFormattedUnitsPre: '',
274
+ tooltipsFormattedUnitsPost: '',
275
+ tooltipsFormattedKeyColors: null,
276
+ tooltipsFormattedKeyColorsShape: 'square',
277
+ tooltipsFormattedKeyLabels: [],
278
+ tooltipsFormattedTableHeaders: null,
279
+ tooltipsFormattedTableData: null,
280
+ tooltipsPointer: true,
281
+ tooltipsPointerOffsetx: 0,
282
+ tooltipsPointerOffsety: 0,
283
+ tooltipsPositionStatic: true,
284
+
285
+ highlightStroke: 'rgba(0,0,0,0)',
286
+ highlightFill: 'rgba(255,255,255,0.7)',
287
+ highlightLinewidth: 1,
288
+
289
+ title: '',
290
+ titleX: null,
291
+ titleY: null,
292
+ titleHalign: 'center',
293
+ titleValign: null,
294
+ titleSize: null,
295
+ titleColor: null,
296
+ titleFont: null,
297
+ titleBold: null,
298
+ titleItalic: null,
299
+
300
+ titleSubtitle: null,
301
+ titleSubtitleSize: null,
302
+ titleSubtitleColor: '#aaa',
303
+ titleSubtitleFont: null,
304
+ titleSubtitleBold: null,
305
+ titleSubtitleItalic: null,
306
+
307
+ key: null,
308
+ keyColors: null,
309
+ keyOffsetx: 0,
310
+ keyOffsety: 0,
311
+ keyLabelsOffsetx: 0,
312
+ keyLabelsOffsety: -1,
313
+ keyLabelsFont: null,
314
+ keyLabelsSize: null,
315
+ keyLabelsColor: null,
316
+ keyLabelsBold: null,
317
+ keyLabelsItalic: null,
318
+
319
+ bubble: false,
320
+ bubbleMaxValue: null,
321
+ bubbleMaxRadius: null,
322
+ bubbleColorsSolid: false,
323
+
324
+ errorbars: null,
325
+ errorbarsColor: 'black',
326
+ errorbarsLinewidth: 1,
327
+ errorbarsCapwidth: 10,
328
+
329
+ trendline: false,
330
+ trendlineColors: ['gray'],
331
+ trendlineLinewidth: 1,
332
+ trendlineMargin: 15,
333
+ trendlineDashed: true,
334
+ trendlineDotted: false,
335
+ trendlineDashArray: null,
336
+ trendlineClipping: null,
337
+
338
+ outofbounds: true
339
+ };
340
+
341
+
342
+
343
+
344
+ //
345
+ // Copy the global object properties to this instance
346
+ //
347
+ RGraph.SVG.getGlobals(this);
348
+
349
+
350
+
351
+
352
+
353
+ //
354
+ // Set the options that the user has provided
355
+ //
356
+ for (i in conf.options) {
357
+ if (typeof i === 'string') {
358
+ this.set(i, conf.options[i]);
359
+ }
360
+ }
361
+
362
+
363
+
364
+
365
+
366
+ // Handles the data that was supplied to the object. If only one dataset
367
+ // was given, convert it into into a multiple dataset style array
368
+ if (this.data[0] && !RGraph.SVG.isArray(this.data[0])) {
369
+ this.data = [];
370
+ this.data[0] = conf.data;
371
+ }
372
+
373
+
374
+
375
+
376
+ // Go through the data converting the various X and Y options
377
+ // from strings to numbers if necessary
378
+ //
379
+ // THIS MESSES UP DATETIME CHART
380
+ //
381
+ //for (var i=0; i<this.data.length; ++i) {
382
+ // for (var j=0; j<this.data[i].length; ++j) {
383
+ // if (typeof this.data[i][j].x === 'string') this.data[i][j].x = parseFloat(this.data[i][j].x);
384
+ // if (typeof this.data[i][j].y === 'string') this.data[i][j].y = parseFloat(this.data[i][j].y);
385
+ // if (typeof this.data[i][j].size === 'string') this.data[i][j].size = parseFloat(this.data[i][j].size);
386
+ // if (typeof this.data[i][j].opacity === 'string') this.data[i][j].opacity = parseFloat(this.data[i][j].opacity);
387
+ // }
388
+ //}
389
+
390
+
391
+
392
+
393
+ //
394
+ // "Decorate" the object with the generic effects if the effects library has been included
395
+ //
396
+ if (RGraph.SVG.FX && typeof RGraph.SVG.FX.decorate === 'function') {
397
+ RGraph.SVG.FX.decorate(this);
398
+ }
399
+
400
+
401
+
402
+
403
+
404
+ // Add the responsive function to the object
405
+ this.responsive = RGraph.SVG.responsive;
406
+
407
+
408
+
409
+
410
+
411
+ var properties = this.properties;
412
+
413
+
414
+ //
415
+ // Convert string X values to timestamps
416
+ //
417
+ if (typeof properties.xaxisScaleMin === 'string') {
418
+ properties.xaxisScaleMin = RGraph.SVG.parseDate(properties.xaxisScaleMin);
419
+ }
420
+
421
+ if (typeof properties.xaxisScaleMax === 'string') {
422
+ properties.xaxisScaleMax = RGraph.SVG.parseDate(properties.xaxisScaleMax);
423
+ }
424
+
425
+ for (var i=0; i<this.data.length; ++i) {
426
+ for (var j=0; j<this.data[i].length; ++j) {
427
+ if (typeof this.data[i][j].x === 'string') {
428
+ this.data[i][j].x = RGraph.SVG.parseDate(this.data[i][j].x);
429
+ }
430
+ }
431
+ }
432
+
433
+
434
+
435
+
436
+
437
+
438
+
439
+ //
440
+ // The draw method draws the Bar chart
441
+ //
442
+ this.draw = function ()
443
+ {
444
+ // Fire the beforedraw event
445
+ RGraph.SVG.fireCustomEvent(this, 'onbeforedraw');
446
+
447
+ // Reset the sequential counter
448
+ this.sequential = 0;
449
+
450
+ // Should the first thing that's done inthe.draw() function
451
+ // except for the onbeforedraw event
452
+ this.width = Number(this.svg.getAttribute('width'));
453
+ this.height = Number(this.svg.getAttribute('height'));
454
+
455
+
456
+
457
+
458
+ //
459
+ // If the labels option is a string then turn it
460
+ // into an array.
461
+ //
462
+ if (properties.xaxisLabels && properties.xaxisLabels.length) {
463
+
464
+ if (typeof properties.xaxisLabels === 'string') {
465
+ properties.xaxisLabels = RGraph.SVG.arrayPad({
466
+ array: [],
467
+ length: properties.xaxisLabelsCount,
468
+ value: properties.xaxisLabels
469
+ });
470
+ }
471
+
472
+ //
473
+ // Label substitution
474
+ //
475
+ for (var i=0; i<properties.xaxisLabels.length; ++i) {
476
+ properties.xaxisLabels[i] = RGraph.SVG.labelSubstitution({
477
+ object: this,
478
+ text: properties.xaxisLabels[i],
479
+ index: i,
480
+ value: this.data[0][i],
481
+ decimals: properties.xaxisLabelsFormattedDecimals || 0,
482
+ unitsPre: properties.xaxisLabelsFormattedUnitsPre || '',
483
+ unitsPost: properties.xaxisLabelsFormattedUnitsPost || '',
484
+ thousand: properties.xaxisLabelsFormattedThousand || ',',
485
+ point: properties.xaxisLabelsFormattedPoint || '.'
486
+ });
487
+ }
488
+ }
489
+
490
+
491
+
492
+
493
+
494
+
495
+
496
+
497
+ // Create the defs tag if necessary
498
+ RGraph.SVG.createDefs(this);
499
+
500
+
501
+
502
+
503
+
504
+ this.graphWidth = this.width - properties.marginLeft - properties.marginRight;
505
+ this.graphHeight = this.height - properties.marginTop - properties.marginBottom;
506
+
507
+
508
+ // Prevents these from growing
509
+ this.coords = [];
510
+ this.coords2 = [];
511
+
512
+
513
+
514
+
515
+ // Parse the colors for gradients
516
+ RGraph.SVG.resetColorsToOriginalValues({object:this});
517
+ this.parseColors();
518
+
519
+
520
+
521
+
522
+ // Work out the maximum value
523
+ for (var ds=0,max=0; ds<this.data.length; ++ds) { // Datasets
524
+ for (var dp=0; dp<this.data[ds].length; ++dp) { // Datapoints
525
+ max = Math.max(
526
+ max,
527
+ this.data[ds][dp].y + (this.data[ds][dp].errorbar ? (typeof this.data[ds][dp].errorbar === 'number' ? this.data[ds][dp].errorbar : this.data[ds][dp].errorbar.max) : 0)
528
+ );
529
+ }
530
+ }
531
+
532
+
533
+
534
+
535
+
536
+
537
+ // A custom, user-specified maximum value
538
+ if (typeof properties.yaxisScaleMax === 'number') {
539
+ max = properties.yaxisScaleMax;
540
+ }
541
+
542
+ // Set the ymin to zero if it's set mirror
543
+ if (properties.yaxisScaleMin === 'mirror' || properties.yaxisScaleMin === 'middle' || properties.yaxisScaleMin === 'center') {
544
+ var mirrorScale = true;
545
+ properties.yaxisScaleMin = 0;
546
+ }
547
+
548
+
549
+ //
550
+ // Generate an appropiate scale
551
+ //
552
+ this.scale = RGraph.SVG.getScale({
553
+ object: this,
554
+ numlabels: properties.yaxisLabelsCount,
555
+ unitsPre: properties.yaxisScaleUnitsPre,
556
+ unitsPost: properties.yaxisScaleUnitsPost,
557
+ max: max,
558
+ min: properties.yaxisScaleMin,
559
+ point: properties.yaxisScalePoint,
560
+ round: properties.yaxisScaleRound,
561
+ thousand: properties.yaxisScaleThousand,
562
+ decimals: properties.yaxisScaleDecimals,
563
+ strict: typeof properties.yaxisScaleMax === 'number',
564
+ formatter: properties.yaxisScaleFormatter
565
+ });
566
+
567
+
568
+
569
+ //
570
+ // Get the scale a second time if the ymin should be
571
+ // mirored
572
+ //
573
+ // Set the ymin to zero if it's set mirror
574
+ if (mirrorScale) {
575
+ this.scale = RGraph.SVG.getScale({
576
+ object: this,
577
+ numlabels: properties.yaxisLabelsCount,
578
+ unitsPre: properties.yaxisScaleUnitsPre,
579
+ unitsPost: properties.yaxisScaleUnitsPost,
580
+ max: this.scale.max,
581
+ min: this.scale.max * -1,
582
+ point: properties.yaxisScalePoint,
583
+ round: false,
584
+ thousand: properties.yaxisScaleThousand,
585
+ decimals: properties.yaxisScaleDecimals,
586
+ strict: typeof properties.yaxisScaleMax === 'number',
587
+ formatter: properties.yaxisScaleFormatter
588
+ });
589
+ }
590
+
591
+ // Now the scale has been generated adopt its max value
592
+ this.max = this.scale.max;
593
+ this.min = this.scale.min;
594
+ properties.yaxisScaleMax = this.scale.max;
595
+ properties.yaxisScaleMin = this.scale.min;
596
+
597
+
598
+
599
+
600
+ // Draw the background first
601
+ RGraph.SVG.drawBackground(this);
602
+
603
+
604
+
605
+
606
+
607
+
608
+
609
+ // Draw the axes under the points
610
+
611
+ RGraph.SVG.drawXAxis(this);
612
+ RGraph.SVG.drawYAxis(this);
613
+
614
+
615
+
616
+
617
+
618
+
619
+ // Create a group for all of the datasets
620
+ var dataset_group = RGraph.SVG.create({
621
+ svg: this.svg,
622
+ type: 'g',
623
+ parent: this.svg.all,
624
+ attr: {
625
+ className: 'scatter_datasets_' + this.uid
626
+ }
627
+ });
628
+
629
+ // Draw the points for all of the datasets
630
+ for (var i=0; i<this.data.length; ++i) {
631
+
632
+ var group = RGraph.SVG.create({
633
+ svg: this.svg,
634
+ type: 'g',
635
+ parent: this.svg.all,
636
+ attr: {
637
+ id: 'scatter_line_' + i + this.uid
638
+ }
639
+ });
640
+
641
+ this.line_groups[i] = group;
642
+
643
+ this.drawPoints({
644
+ index: i,
645
+ data: this.data[i],
646
+ group: dataset_group
647
+ });
648
+
649
+ // Draw a line for this dataset
650
+ if (properties.line === true || (typeof properties.line === 'object' && properties.line[i] === true)) {
651
+ this.drawLine({
652
+ index: i,
653
+ coords: this.coords2[i],
654
+ });
655
+ }
656
+ }
657
+
658
+
659
+
660
+
661
+
662
+
663
+
664
+
665
+
666
+ //
667
+ // Draw a trendline if requested
668
+ //
669
+ if (properties.trendline) {
670
+ for (var i=0; i<this.data.length; ++i) {
671
+ if (properties.trendline === true || (typeof properties.trendline === 'object' && properties.trendline[i] === true) ) {
672
+ this.drawTrendline(i);
673
+ }
674
+ }
675
+ }
676
+
677
+
678
+
679
+
680
+
681
+
682
+
683
+
684
+ // Draw the key
685
+ if (typeof properties.key !== null && RGraph.SVG.drawKey) {
686
+ RGraph.SVG.drawKey(this);
687
+ } else if (!RGraph.SVG.isNull(properties.key)) {
688
+ alert('The drawKey() function does not exist - have you forgotten to include the key library?');
689
+ }
690
+
691
+
692
+
693
+
694
+ // Add the event listener that clears the highlight rect if
695
+ // there is any. Must be MOUSEDOWN (ie before the click event)
696
+ //var obj = this;
697
+ //document.body.addEventListener('mousedown', function (e)
698
+ //{
699
+ //RGraph.SVG.removeHighlight(obj);
700
+
701
+ //}, false);
702
+
703
+
704
+
705
+
706
+
707
+
708
+
709
+
710
+ //
711
+ // Allow the addition of custom text via the
712
+ // text: property.
713
+ //
714
+ RGraph.SVG.addCustomText(this);
715
+
716
+
717
+
718
+
719
+
720
+
721
+
722
+
723
+
724
+
725
+ // Draw any custom lines that have been defined
726
+ RGraph.SVG.drawHorizontalLines(this);
727
+
728
+
729
+
730
+
731
+
732
+
733
+
734
+
735
+
736
+
737
+ //
738
+ // Fire the onfirstdraw event
739
+ //
740
+ if (this.firstDraw) {
741
+ this.firstDraw = false;
742
+ RGraph.SVG.fireCustomEvent(this, 'onfirstdraw');
743
+ }
744
+
745
+
746
+ // Fire the draw event
747
+ RGraph.SVG.fireCustomEvent(this, 'ondraw');
748
+
749
+
750
+
751
+
752
+
753
+
754
+
755
+ //
756
+ // Install any inline responsive configuration. This
757
+ // should be last in the draw function - even after
758
+ // the draw events.
759
+ //
760
+ RGraph.SVG.installInlineResponsive(this);
761
+
762
+
763
+
764
+
765
+
766
+
767
+
768
+
769
+
770
+
771
+
772
+
773
+
774
+ return this;
775
+ };
776
+
777
+
778
+
779
+
780
+
781
+
782
+
783
+
784
+ //
785
+ // New create() shortcut function
786
+ // For example:
787
+ // this.create('rect,x:0,y:0,width:100,height:100'[,parent]);
788
+ //
789
+ // @param str string The tag definition to parse and create
790
+ // @param object The (optional) parent element
791
+ // @return object The new tag
792
+ //
793
+ this.create = function (str)
794
+ {
795
+ var def = RGraph.SVG.create.parseStr(this, str);
796
+ def.svg = this.svg;
797
+
798
+ // By default the parent is the SVG tag - but if
799
+ // requested then change it to the tag that has
800
+ // been given
801
+ if (arguments[1]) {
802
+ def.parent = arguments[1];
803
+ }
804
+
805
+ return RGraph.SVG.create(def);
806
+ };
807
+
808
+
809
+
810
+
811
+
812
+
813
+
814
+
815
+ //
816
+ // Draws the Points
817
+ //
818
+ // @param opt object Options to the function which can consist of:
819
+ // o index: The numerical index of the DATASET
820
+ // o dataset: The dataset.
821
+ //
822
+ this.drawPoints = function (opt)
823
+ {
824
+ var index = opt.index,
825
+ data = opt.data,
826
+ group = opt.group;
827
+
828
+ // Initialise the array for coordinates
829
+ if (!this.coords2[index]) {
830
+ this.coords2[index] = [];
831
+ }
832
+
833
+ //
834
+ // Create the <g> tag that the datapoints are added to
835
+ //
836
+ var group = RGraph.SVG.create({
837
+ svg: this.svg,
838
+ type: 'g',
839
+ parent: group,
840
+ attr: {
841
+ className: 'scatter_dataset_' + index + '_' + this.uid
842
+ }
843
+ });
844
+
845
+ // Loop through the data
846
+ for (var i=0; i<data.length; ++i) {
847
+
848
+ var point = data[i];
849
+
850
+ if (typeof point.x === 'number'&& typeof point.y === 'number') {
851
+
852
+ var ret = this.drawSinglePoint({
853
+ dataset: data,
854
+ datasetIdx: index,
855
+ point: point,
856
+ index: i,
857
+ group: group, // The SVG <g> tag the points are added to
858
+ sequential: this.sequential
859
+ });
860
+
861
+ // Add the coordinates to the coords arrays
862
+ this.coords.push({
863
+ x: ret.x,
864
+ y: ret.y,
865
+ z: ret.size,
866
+ type: ret.type,
867
+ element: ret.mark,
868
+ object: this
869
+ });
870
+
871
+ this.coords2[index][i] = {
872
+ x: ret.x,
873
+ y: ret.y,
874
+ z: ret.size,
875
+ type: ret.type,
876
+ element: ret.mark,
877
+ object: this
878
+ };
879
+
880
+ this.sequential++
881
+ }
882
+
883
+
884
+
885
+
886
+
887
+
888
+
889
+
890
+
891
+
892
+
893
+
894
+
895
+ //
896
+ // Add tooltip highlight to the point
897
+ //
898
+ if ( (typeof data[i].tooltip === 'string' && data[i].tooltip) || (typeof data[i].tooltip === 'number') || (typeof properties.tooltips === 'string') ) {
899
+
900
+ // Convert the tooltip to a string
901
+ data[i].tooltip = String(data[i].tooltip);
902
+
903
+ // Make the tooltipsEvent default to click
904
+ if (properties.tooltipsEvent !== 'mousemove') {
905
+ properties.tooltipsEvent = 'click';
906
+ }
907
+
908
+ if (!group_tooltip_hotspots) {
909
+ var group_tooltip_hotspots = RGraph.SVG.create({
910
+ svg: this.svg,
911
+ parent: this.svg.all,
912
+ type: 'g',
913
+ attr: {
914
+ className: 'rgraph-scatter-tooltip-hotspots'
915
+ }
916
+ });
917
+ }
918
+
919
+ var rect = RGraph.SVG.create({
920
+ svg: this.svg,
921
+ parent: this.svg.all,
922
+ type: 'rect',
923
+ parent: group_tooltip_hotspots,
924
+ attr: {
925
+ x: ret.x - (ret.size / 2),
926
+ y: ret.y - (ret.size / 2),
927
+ width: ret.size,
928
+ height: ret.size,
929
+ fill: 'transparent',
930
+ stroke: 'transparent',
931
+ 'stroke-width': 3
932
+ },
933
+ style: {
934
+ cursor: 'pointer'
935
+ }
936
+ });
937
+
938
+ // Add the hotspot to the original tickmark
939
+ ret.mark.hotspot = rect;
940
+
941
+ (function (dataset, index, seq, obj)
942
+ {
943
+ rect.addEventListener(properties.tooltipsEvent, function (e)
944
+ {
945
+ var tooltip = RGraph.SVG.REG.get('tooltip');
946
+
947
+ if (tooltip && tooltip.__dataset__ === dataset && tooltip.__index__ === index && tooltip.__object__.uid === obj.uid) {
948
+ return;
949
+ }
950
+
951
+ obj.removeHighlight();
952
+
953
+ // Show the tooltip
954
+ RGraph.SVG.tooltip({
955
+ object: obj,
956
+ dataset: dataset,
957
+ index: index,
958
+ sequentialIndex: seq,
959
+ text: typeof properties.tooltips === 'string' ? properties.tooltips : obj.data[dataset][index].tooltip,
960
+ event: e
961
+ });
962
+
963
+
964
+ // Highlight the shape that has been clicked on
965
+ if (RGraph.SVG.REG.get('tooltip')) {
966
+ obj.highlight(this);
967
+ }
968
+
969
+ }, false);
970
+
971
+ // Install the event listener that changes the
972
+ // cursor if necessary
973
+ if (properties.tooltipsEvent === 'click') {
974
+ rect.addEventListener('mousemove', function (e)
975
+ {
976
+ e.target.style.cursor = 'pointer';
977
+ }, false);
978
+ }
979
+
980
+ }(index, i, this.sequential - 1, this));
981
+ }
982
+ }
983
+ };
984
+
985
+
986
+
987
+
988
+
989
+
990
+
991
+
992
+ //
993
+ // Draws a single point on the chart
994
+ //
995
+ this.drawSinglePoint = function (opt)
996
+ {
997
+ var dataset = opt.dataset,
998
+ datasetIdx = opt.datasetIdx,
999
+ seq = opt.sequential,
1000
+ point = opt.point,
1001
+ index = opt.index,
1002
+ valueX = opt.point.x,
1003
+ valueY = opt.point.y,
1004
+ conf = opt.point || {},
1005
+ group = opt.group,
1006
+ coordX = opt.coordx = this.getXCoord(valueX),
1007
+ coordY = opt.coordy = this.getYCoord(valueY);
1008
+
1009
+
1010
+
1011
+
1012
+ // Get the above label
1013
+ if (conf.labelsAbove) {
1014
+ var above = true;
1015
+ } else if (conf.labelAbove) {
1016
+ var above = true;
1017
+ } else if (conf.above) {
1018
+ var above = true;
1019
+ }
1020
+
1021
+
1022
+
1023
+
1024
+
1025
+
1026
+ // Allow shape to be synonym for type
1027
+ if (typeof conf.type === 'undefined' && typeof conf.shape !== 'undefined') {
1028
+ conf.type = conf.shape;
1029
+ }
1030
+
1031
+
1032
+
1033
+
1034
+
1035
+
1036
+ // set the type to the default if its not set
1037
+ if (typeof conf.type !== 'string') {
1038
+ if (typeof properties.tickmarksStyle === 'string') {
1039
+ conf.type = properties.tickmarksStyle;
1040
+ } else if (typeof properties.tickmarksStyle === 'object' && typeof properties.tickmarksStyle[datasetIdx] === 'string') {
1041
+ conf.type = properties.tickmarksStyle[datasetIdx];
1042
+ } else {
1043
+ conf.type = 'cross';
1044
+ }
1045
+ }
1046
+
1047
+
1048
+
1049
+
1050
+
1051
+
1052
+
1053
+
1054
+
1055
+
1056
+
1057
+
1058
+ // set the size to the default if its not set
1059
+ if (typeof conf.size !== 'number' && typeof properties.tickmarksSize === 'number') {
1060
+ conf.size = properties.tickmarksSize;
1061
+ } else if (typeof conf.size !== 'number' && typeof properties.tickmarksSize === 'object' && typeof properties.tickmarksSize[datasetIdx] === 'number') {
1062
+ conf.size = properties.tickmarksSize[datasetIdx];
1063
+ }
1064
+
1065
+
1066
+
1067
+
1068
+
1069
+
1070
+
1071
+ // Set the color to the default if its not set and then blacck if thats not set either
1072
+ if (typeof conf.color === 'string') {
1073
+ // nada
1074
+ } else if (typeof properties.colors[datasetIdx] === 'string') {
1075
+ conf.color = properties.colors[datasetIdx];
1076
+ } else {
1077
+ conf.color = 'black';
1078
+ }
1079
+
1080
+
1081
+
1082
+
1083
+
1084
+
1085
+
1086
+ // Set the opacity of this point
1087
+ if (typeof conf.opacity === 'undefined') {
1088
+ conf.opacity = 1;
1089
+ } else if (typeof conf.opacity === 'number') {
1090
+ // nada
1091
+ }
1092
+
1093
+
1094
+
1095
+
1096
+
1097
+
1098
+ // Draw the errorbar here
1099
+ //
1100
+ // First convert the errorbar information in the data into an array in the properties
1101
+ //
1102
+ properties.errorbars = [];
1103
+ for (var ds=0,max=0; ds<this.data.length; ++ds) {
1104
+ for (var idx=0; idx<this.data[ds].length; ++idx) {
1105
+ properties.errorbars.push(this.data[ds][idx].errorbar);
1106
+ }
1107
+ }
1108
+
1109
+ this.drawErrorbar({
1110
+ object: this,
1111
+ dataset: datasetIdx,
1112
+ index: index,
1113
+ group: group,
1114
+ sequential: seq,
1115
+ x: coordX,
1116
+ y: coordY,
1117
+ valueX: valueX,
1118
+ valueY: valueY,
1119
+ parent: group
1120
+ });
1121
+
1122
+
1123
+
1124
+
1125
+
1126
+
1127
+
1128
+
1129
+
1130
+
1131
+
1132
+ // Bubble charts are drawn by their own function
1133
+ if (properties.bubble) {
1134
+ //return this.drawBubble(opt, conf);
1135
+ this.drawBubble(opt, conf);
1136
+ }
1137
+
1138
+
1139
+
1140
+
1141
+
1142
+
1143
+
1144
+
1145
+
1146
+
1147
+
1148
+
1149
+
1150
+
1151
+
1152
+
1153
+
1154
+
1155
+
1156
+
1157
+
1158
+ // Handle the various shapes for tickmarks here
1159
+ switch (conf.type) {
1160
+ case 'image:' + conf.type.substr(6):
1161
+
1162
+ var src = conf.type.substr(6);
1163
+
1164
+ var img = new Image();
1165
+ img.src = src;
1166
+
1167
+ var mark = RGraph.SVG.create({
1168
+ svg: this.svg,
1169
+ type: 'image',
1170
+ parent: group,
1171
+ attr: {
1172
+ preserveAspectRatio: 'xMidYMid meet',
1173
+ 'xlink:href': src,
1174
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
1175
+ }
1176
+ });
1177
+
1178
+ // Once the image has loaded the x/y/width/height can be set
1179
+ // (both the image and it's hotspot)
1180
+ img.onload = function ()
1181
+ {
1182
+ var x = coordX - (img.width / 2),
1183
+ y = coordY - (img.height / 2),
1184
+ w = img.width,
1185
+ h = img.height;
1186
+
1187
+ mark.setAttribute('x', x);
1188
+ mark.setAttribute('y', y);
1189
+ mark.setAttribute('width', w);
1190
+ mark.setAttribute('height', h);
1191
+
1192
+ if (mark && mark.hotspot) {
1193
+ mark.hotspot.setAttribute('x', x);
1194
+ mark.hotspot.setAttribute('y', y);
1195
+ mark.hotspot.setAttribute('width', w);
1196
+ mark.hotspot.setAttribute('height', h);
1197
+ }
1198
+ };
1199
+
1200
+ break;
1201
+
1202
+ case 'triangle':
1203
+ var mark = RGraph.SVG.create({
1204
+ svg: this.svg,
1205
+ type: 'path',
1206
+ parent: group,
1207
+ attr: {
1208
+ d: 'M {1} {2} L {3} {4} L {5} {6}'.format(
1209
+ coordX - (conf.size / 2),
1210
+ coordY + (conf.size / 2),
1211
+ coordX,
1212
+ coordY - (conf.size / 2),
1213
+ coordX + (conf.size / 2),
1214
+ coordY + (conf.size / 2)
1215
+ ),
1216
+ fill: conf.color,
1217
+ 'fill-opacity': conf.opacity,
1218
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
1219
+ }
1220
+ });
1221
+ break;
1222
+
1223
+ case 'plus':
1224
+ var mark = RGraph.SVG.create({
1225
+ svg: this.svg,
1226
+ type: 'path',
1227
+ parent: group,
1228
+ attr: {
1229
+ d: 'M {1} {2} L {3} {4} M {5} {6} L {7} {8}'.format(
1230
+ coordX - (conf.size / 2),
1231
+ coordY,
1232
+ coordX + (conf.size / 2),
1233
+ coordY,
1234
+ coordX,
1235
+ coordY - (conf.size / 2),
1236
+ coordX,
1237
+ coordY + (conf.size / 2)
1238
+ ),
1239
+ stroke: conf.color,
1240
+ 'stroke-opacity': conf.opacity,
1241
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
1242
+ }
1243
+ });
1244
+ break;
1245
+
1246
+ case 'square':
1247
+ case 'rect':
1248
+ var mark = RGraph.SVG.create({
1249
+ svg: this.svg,
1250
+ type: 'rect',
1251
+ parent: group,
1252
+ attr: {
1253
+ x: coordX - (conf.size / 2),
1254
+ y: coordY - (conf.size / 2),
1255
+ width: conf.size,
1256
+ height: conf.size,
1257
+ fill: conf.color,
1258
+ 'fill-opacity': conf.opacity,
1259
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
1260
+ }
1261
+ });
1262
+ break;
1263
+
1264
+
1265
+
1266
+ case 'dot':
1267
+ case 'circle':
1268
+ var mark = RGraph.SVG.create({
1269
+ svg: this.svg,
1270
+ type: 'circle',
1271
+ parent: group,
1272
+ attr: {
1273
+ cx: coordX,
1274
+ cy: coordY,
1275
+ r: conf.size / 2,
1276
+ fill: conf.color,
1277
+ 'fill-opacity': conf.opacity,
1278
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
1279
+ }
1280
+ });
1281
+ break;
1282
+
1283
+
1284
+
1285
+ case 'cross':
1286
+ default:
1287
+ var mark = RGraph.SVG.create({
1288
+ svg: this.svg,
1289
+ type: 'path',
1290
+ parent: group,
1291
+ attr: {
1292
+ d: 'M {1} {2} L {3} {4} M {5} {6} L {7} {8}'.format(
1293
+ coordX - (conf.size / 2), coordY - (conf.size / 2),
1294
+ coordX + (conf.size / 2), coordY + (conf.size / 2),
1295
+ coordX - (conf.size / 2), coordY + (conf.size / 2),
1296
+ coordX + (conf.size / 2), coordY - (conf.size / 2)
1297
+ ),
1298
+ stroke: conf.color,
1299
+ 'stroke-opacity': conf.opacity,
1300
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
1301
+ }
1302
+ });
1303
+ break;
1304
+ }
1305
+
1306
+ //
1307
+ // Draw the above label if it's present
1308
+ //
1309
+ if (typeof conf.above === 'string' || (typeof conf.above !== 'string' && conf.above) ) {
1310
+ this.drawLabelsAbove({
1311
+ point: conf,
1312
+ coordX: coordX,
1313
+ coordY: coordY
1314
+ });
1315
+ }
1316
+
1317
+
1318
+
1319
+
1320
+ // Add some data attributes that save various values
1321
+ mark.setAttribute('data-index', index);
1322
+ mark.setAttribute('data-dataset', datasetIdx);
1323
+ mark.setAttribute('data-original-opacity', conf.opacity);
1324
+ mark.setAttribute('data-original-color', conf.color);
1325
+ mark.setAttribute('data-original-coordx', coordX);
1326
+ mark.setAttribute('data-original-coordy', coordY);
1327
+ mark.setAttribute('data-size', conf.size);
1328
+ mark.setAttribute('data-sequential', seq);
1329
+ mark.setAttribute('data-type', conf.type);
1330
+
1331
+ return {
1332
+ x: coordX,
1333
+ y: coordY,
1334
+ size: conf.type.substr(0,6) === 'image:' ? img.width : conf.size,
1335
+ mark: mark,
1336
+ type: conf.type
1337
+ };
1338
+ };
1339
+
1340
+
1341
+
1342
+
1343
+
1344
+
1345
+
1346
+ // Draw a bubble on a bubble chart
1347
+ this.drawBubble = function (opt, conf)
1348
+ {
1349
+ var size = (conf.z / properties.bubbleMaxValue) * properties.bubbleMaxRadius;
1350
+
1351
+ var color = RGraph.SVG.parseColorRadial({
1352
+ object: this,
1353
+ color: properties.bubbleColorsSolid ? conf.color : 'Gradient(white:' + conf.color + ')',
1354
+ cx: opt.coordx + (size / 4),
1355
+ cy: opt.coordy - (size / 4),
1356
+ fx: opt.coordx + (size / 4),
1357
+ fy: opt.coordy - (size / 4),
1358
+ r: size * 1.5
1359
+ });
1360
+
1361
+ var circle = RGraph.SVG.create({
1362
+ svg: this.svg,
1363
+ type: 'circle',
1364
+ attr: {
1365
+ cx: opt.coordx,
1366
+ cy: opt.coordy,
1367
+ r: size,
1368
+ fill: color,
1369
+ 'fill-opacity': conf.opacity,
1370
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : '',
1371
+ }
1372
+ });
1373
+
1374
+ // Add some data attributes that save various values
1375
+ circle.setAttribute('data-index', opt.index);
1376
+ circle.setAttribute('data-dataset', opt.datasetIdx);
1377
+ circle.setAttribute('data-original-opacity', conf.opacity);
1378
+ circle.setAttribute('data-original-color', conf.color);
1379
+ circle.setAttribute('data-original-coordx', opt.coordx);
1380
+ circle.setAttribute('data-original-coordy', opt.coordy);
1381
+ circle.setAttribute('data-size', size);
1382
+ circle.setAttribute('data-sequential', opt.sequential);
1383
+ circle.setAttribute('data-type', 'bubble');
1384
+
1385
+ return {
1386
+ x: opt.coordx,
1387
+ y: opt.coordy,
1388
+ z: opt.coordz
1389
+ };
1390
+ };
1391
+
1392
+
1393
+
1394
+
1395
+
1396
+
1397
+
1398
+
1399
+ //
1400
+ // This functions draws a line if required
1401
+ //
1402
+ this.drawLine = function (opt)
1403
+ {
1404
+ var linewidth = 1,
1405
+ color = 'black';
1406
+
1407
+
1408
+
1409
+ // Calculate the linewidth
1410
+ if (typeof properties.lineLinewidth === 'object' && typeof properties.lineLinewidth[opt.index] === 'number') {
1411
+ linewidth = properties.lineLinewidth[opt.index];
1412
+ } else if (typeof properties.lineLinewidth === 'number') {
1413
+ linewidth = properties.lineLinewidth;
1414
+ } else {
1415
+ linewidth = 1;
1416
+ }
1417
+
1418
+
1419
+
1420
+
1421
+
1422
+
1423
+ // Determine the color
1424
+ if (!RGraph.SVG.isNull(properties.lineColors) && properties.lineColors && properties.lineColors[opt.index]) {
1425
+ color = properties.lineColors[opt.index];
1426
+ } else if (!RGraph.SVG.isNull(properties.colors) && properties.colors.length && typeof properties.colors[opt.index] === 'string') {
1427
+ color = properties.colors[opt.index];
1428
+ } else if (typeof properties.lineColors === 'string') {
1429
+ color = properties.lineColors;
1430
+ } else {
1431
+ color = 'black';
1432
+ }
1433
+
1434
+
1435
+
1436
+
1437
+
1438
+ for (var i=0,path=''; i<this.coords2[opt.index].length; ++i) {
1439
+ path += '{1} {2} {3} '.format(
1440
+ i === 0 ? 'M' : 'L',
1441
+ this.coords2[opt.index][i].x,
1442
+ this.coords2[opt.index][i].y
1443
+ );
1444
+ }
1445
+
1446
+ RGraph.SVG.create({
1447
+ svg: this.svg,
1448
+ type: 'path',
1449
+ parent: this.line_groups[opt.index],
1450
+ attr: {
1451
+ d: path,
1452
+ fill: 'transparent',
1453
+ stroke: color,
1454
+ 'stroke-width': linewidth,
1455
+ 'stroke-linecap': 'round',
1456
+ 'stroke-linejoin': 'round',
1457
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
1458
+ }
1459
+ });
1460
+ };
1461
+
1462
+
1463
+
1464
+
1465
+
1466
+
1467
+
1468
+
1469
+ //
1470
+ // This function can be used to retrieve the relevant X coordinate for a
1471
+ // particular value.
1472
+ //
1473
+ // @param int value The value to get the X coordinate for
1474
+ //
1475
+ this.getXCoord = function (value)
1476
+ {
1477
+ var x;
1478
+
1479
+ if (value > properties.xaxisScaleMax) {
1480
+ return null;
1481
+ }
1482
+
1483
+ if (value < properties.xaxisScaleMin) {
1484
+ return null;
1485
+ }
1486
+
1487
+ x = ((value - properties.xaxisScaleMin) / (properties.xaxisScaleMax - properties.xaxisScaleMin));
1488
+ x *= (this.width - properties.marginLeft - properties.marginRight);
1489
+
1490
+ x = properties.marginLeft + x;
1491
+
1492
+ return x;
1493
+ };
1494
+
1495
+
1496
+
1497
+
1498
+
1499
+
1500
+
1501
+
1502
+ //
1503
+ // This function can be used to retrieve the relevant Y coordinate for a
1504
+ // particular value.
1505
+ //
1506
+ // @param int value The value to get the Y coordinate for
1507
+ //
1508
+ this.getYCoord = function (value)
1509
+ {
1510
+ if (value > this.scale.max && properties.outofbounds === false) {
1511
+ return null;
1512
+ }
1513
+
1514
+ var y, xaxispos = properties.xaxispos;
1515
+
1516
+ if (value < this.scale.min && properties.outofbounds === false) {
1517
+ return null;
1518
+ }
1519
+
1520
+ y = ((value - this.scale.min) / (this.scale.max - this.scale.min));
1521
+ y *= (this.height - properties.marginTop - properties.marginBottom);
1522
+
1523
+ y = this.height - properties.marginBottom - y;
1524
+
1525
+ return y;
1526
+ };
1527
+
1528
+
1529
+
1530
+
1531
+
1532
+
1533
+
1534
+
1535
+ //
1536
+ // This function can be used to highlight a bar on the chart
1537
+ //
1538
+ // @param object rect The rectangle to highlight
1539
+ //
1540
+ this.highlight = function (rect)
1541
+ {
1542
+ var cx = parseFloat(rect.getAttribute('x')) + (parseFloat(rect.getAttribute('width')) / 2),
1543
+ cy = parseFloat(rect.getAttribute('y')) + (parseFloat(rect.getAttribute('height')) / 2),
1544
+ radius = parseFloat(rect.getAttribute('width')) + 1;
1545
+
1546
+ var highlight = RGraph.SVG.create({
1547
+ svg: this.svg,
1548
+ type: 'circle',
1549
+ parent: this.svg.all,
1550
+ attr: {
1551
+ stroke: properties.highlightStroke,
1552
+ fill: properties.highlightFill,
1553
+ cx: cx,
1554
+ cy: cy,
1555
+ r: radius,
1556
+ 'stroke-width': properties.highlightLinewidth
1557
+ },
1558
+ style: {
1559
+ pointerEvents: 'none'
1560
+ }
1561
+ });
1562
+
1563
+
1564
+ // Store the highlight rect in the rebistry so
1565
+ // it can be cleared later
1566
+ RGraph.SVG.REG.set('highlight', highlight);
1567
+
1568
+
1569
+
1570
+
1571
+ //rect.setAttribute('stroke', properties.highlightStroke);
1572
+ //rect.setAttribute('stroke-width', properties.highlightLinewidth);
1573
+ //rect.setAttribute('fill', properties.highlightFill);
1574
+
1575
+ // Store the highlight rect in the registry so
1576
+ // it can be reset later
1577
+ //RGraph.SVG.REG.set('highlight', rect);
1578
+ };
1579
+
1580
+
1581
+
1582
+
1583
+
1584
+
1585
+
1586
+
1587
+ //
1588
+ // Draws the labelsAbove
1589
+ //
1590
+ // @param opt An object that consists of various arguments to the function
1591
+ //
1592
+ this.drawLabelsAbove = function (opt)
1593
+ {
1594
+ var conf = opt.point,
1595
+ coordX = opt.coordX,
1596
+ coordY = opt.coordY;
1597
+
1598
+
1599
+ // Facilitate labelsAboveSpecific
1600
+ if (typeof conf.above === 'string') {
1601
+ var str = conf.above;
1602
+ } else {
1603
+
1604
+ conf.x = RGraph.SVG.numberFormat({
1605
+ object: this,
1606
+ num: conf.x.toFixed(properties.labelsAboveXDecimals ),
1607
+ prepend: typeof properties.labelsAboveXUnitsPre === 'string' ? properties.labelsAboveXUnitsPre : null,
1608
+ append: typeof properties.labelsAboveXUnitsPost === 'string' ? properties.labelsAboveXUnitsPost : null,
1609
+ point: typeof properties.labelsAboveXPoint === 'string' ? properties.labelsAboveXPoint : null,
1610
+ thousand: typeof properties.labelsAboveXThousand === 'string' ? properties.labelsAboveXThousand : null,
1611
+ formatter: typeof properties.labelsAboveXFormatter === 'function' ? properties.labelsAboveXFormatter : null
1612
+ });
1613
+
1614
+ conf.y = RGraph.SVG.numberFormat({
1615
+ object: this,
1616
+ num: conf.y.toFixed(properties.labelsAboveYDecimals ),
1617
+ prepend: typeof properties.labelsAboveYUnitsPre === 'string' ? properties.labelsAboveYUnitsPre : null,
1618
+ append: typeof properties.labelsAboveYUnitsPost === 'string' ? properties.labelsAboveYUnitsPost : null,
1619
+ point: typeof properties.labelsAboveYPoint === 'string' ? properties.labelsAboveYPoint : null,
1620
+ thousand: typeof properties.labelsAboveYThousand === 'string' ? properties.labelsAboveYThousand : null,
1621
+ formatter: typeof properties.labelsAboveYFormatter === 'function' ? properties.labelsAboveYFormatter : null
1622
+ });
1623
+
1624
+ var str = '{1}{2}{3}'.format(
1625
+ conf.x,
1626
+ properties.labelsAboveSeparator,
1627
+ conf.y
1628
+ );
1629
+ }
1630
+
1631
+ // Get the text configuration
1632
+ var textConf = RGraph.SVG.getTextConf({
1633
+ object: this,
1634
+ prefix: 'labelsAbove'
1635
+ });
1636
+
1637
+ // Add the text to the scene
1638
+ var text = RGraph.SVG.text({
1639
+ object: this,
1640
+ parent: this.svg.all,
1641
+ tag: 'labels.above',
1642
+
1643
+ text: str,
1644
+
1645
+ x: parseFloat(coordX) + properties.labelsAboveOffsetx,
1646
+ y: parseFloat(coordY) + properties.labelsAboveOffsety,
1647
+
1648
+ halign: properties.labelsAboveHalign,
1649
+ valign: properties.labelsAboveValign,
1650
+
1651
+ font: textConf.font,
1652
+ size: textConf.size,
1653
+ bold: textConf.bold,
1654
+ italic: textConf.italic,
1655
+ color: textConf.color,
1656
+
1657
+ background: properties.labelsAboveBackground || null,
1658
+ padding: properties.labelsAboveBackgroundPadding || 0
1659
+ });
1660
+
1661
+ if (this.isTrace) {
1662
+ text.setAttribute(
1663
+ 'clip-path',
1664
+ 'url(#trace-effect-clip)'
1665
+ );
1666
+ }
1667
+ };
1668
+
1669
+
1670
+
1671
+
1672
+
1673
+
1674
+
1675
+
1676
+ //
1677
+ // This allows for easy specification of gradients
1678
+ //
1679
+ this.parseColors = function ()
1680
+ {
1681
+
1682
+ // TODO Loop thru the data parsing the color for gradients too
1683
+
1684
+ // Save the original colors so that they can be restored when
1685
+ // the canvas is cleared
1686
+ if (!Object.keys(this.originalColors).length) {
1687
+ this.originalColors = {
1688
+ colors: RGraph.SVG.arrayClone(properties.colors),
1689
+ backgroundGridColor: RGraph.SVG.arrayClone(properties.backgroundGridColor),
1690
+ highlightFill: RGraph.SVG.arrayClone(properties.highlightFill),
1691
+ backgroundColor: RGraph.SVG.arrayClone(properties.backgroundColor)
1692
+ }
1693
+ }
1694
+
1695
+
1696
+ // colors
1697
+ var colors = properties.colors;
1698
+
1699
+ // IMPORTANT: Bubble chart gradients are parse in the drawBubble()
1700
+ // function below
1701
+ if (colors && !properties.bubble) {
1702
+ for (var i=0; i<colors.length; ++i) {
1703
+ colors[i] = RGraph.SVG.parseColorLinear({
1704
+ object: this,
1705
+ color: colors[i]
1706
+ });
1707
+ }
1708
+ }
1709
+
1710
+ properties.backgroundGridColor = RGraph.SVG.parseColorLinear({object: this, color: properties.backgroundGridColor});
1711
+ properties.highlightFill = RGraph.SVG.parseColorLinear({object: this, color: properties.highlightFill});
1712
+ properties.backgroundColor = RGraph.SVG.parseColorLinear({object: this, color: properties.backgroundColor});
1713
+ };
1714
+
1715
+
1716
+
1717
+
1718
+
1719
+
1720
+
1721
+
1722
+ //
1723
+ // Using a function to add events makes it easier to facilitate method
1724
+ // chaining
1725
+ //
1726
+ // @param string type The type of even to add
1727
+ // @param function func
1728
+ //
1729
+ this.on = function (type, func)
1730
+ {
1731
+ if (type.substr(0,2) !== 'on') {
1732
+ type = 'on' + type;
1733
+ }
1734
+
1735
+ RGraph.SVG.addCustomEventListener(this, type, func);
1736
+
1737
+ return this;
1738
+ };
1739
+
1740
+
1741
+
1742
+
1743
+
1744
+
1745
+
1746
+
1747
+ //
1748
+ // Used in chaining. Runs a function there and then - not waiting for
1749
+ // the events to fire (eg the onbeforedraw event)
1750
+ //
1751
+ // @param function func The function to execute
1752
+ //
1753
+ this.exec = function (func)
1754
+ {
1755
+ func(this);
1756
+
1757
+ return this;
1758
+ };
1759
+
1760
+
1761
+
1762
+
1763
+
1764
+
1765
+
1766
+
1767
+ //
1768
+ // Remove highlight from the chart (tooltips)
1769
+ //
1770
+ this.removeHighlight = function ()
1771
+ {
1772
+ RGraph.SVG.removeHighlight();
1773
+ };
1774
+
1775
+
1776
+
1777
+
1778
+
1779
+
1780
+
1781
+ //
1782
+ // Draws a single errorbar
1783
+ //
1784
+ this.drawErrorbar = function (opt)
1785
+ {
1786
+ // Get the error bar value
1787
+ var max = RGraph.SVG.getErrorbarsMaxValue({
1788
+ object: this,
1789
+ index: opt.sequential
1790
+ });
1791
+
1792
+
1793
+ // Get the error bar value
1794
+ var min = RGraph.SVG.getErrorbarsMinValue({
1795
+ object: this,
1796
+ index: opt.sequential
1797
+ });
1798
+
1799
+ if (!max && !min) {
1800
+ return;
1801
+ }
1802
+
1803
+ var linewidth = RGraph.SVG.getErrorbarsLinewidth({object: this, index: opt.sequential}),
1804
+ color = RGraph.SVG.getErrorbarsColor({object: this, index: opt.sequential}),
1805
+ capwidth = RGraph.SVG.getErrorbarsCapWidth({object: this, index: opt.sequential}),
1806
+ halfCapWidth = capwidth / 2;
1807
+
1808
+
1809
+
1810
+
1811
+
1812
+
1813
+ if (max !== 0 || min !== 0) {
1814
+
1815
+ var y1 = this.getYCoord(opt.valueY + max)
1816
+ y2 = this.getYCoord(opt.valueY - min);
1817
+
1818
+ // Draw the UPPER vertical line
1819
+ var errorbarLine = RGraph.SVG.create({
1820
+ svg: this.svg,
1821
+ type: 'line',
1822
+ parent: opt.parent,
1823
+ attr: {
1824
+ x1: opt.x,
1825
+ y1: opt.y,
1826
+ x2: opt.x,
1827
+ y2: y1,
1828
+ stroke: color,
1829
+ 'stroke-width': linewidth,
1830
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
1831
+ }
1832
+ });
1833
+
1834
+
1835
+ // Draw the cap to the UPPER line
1836
+ var errorbarCap = RGraph.SVG.create({
1837
+ svg: this.svg,
1838
+ type: 'line',
1839
+ parent: opt.parent,
1840
+ attr: {
1841
+ x1: opt.x - halfCapWidth,
1842
+ y1: y1,
1843
+ x2: opt.x + halfCapWidth,
1844
+ y2: y1,
1845
+ stroke: color,
1846
+ 'stroke-width': linewidth,
1847
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
1848
+ }
1849
+ });
1850
+ }
1851
+
1852
+
1853
+
1854
+
1855
+
1856
+
1857
+
1858
+
1859
+
1860
+
1861
+
1862
+
1863
+
1864
+
1865
+ // Draw the minimum errorbar if necessary
1866
+ if (typeof min === 'number') {
1867
+
1868
+ var errorbarLine = RGraph.SVG.create({
1869
+ svg: this.svg,
1870
+ type: 'line',
1871
+ parent: opt.parent,
1872
+ attr: {
1873
+ x1: opt.x,
1874
+ y1: opt.y,
1875
+ x2: opt.x,
1876
+ y2: y2,
1877
+ stroke: color,
1878
+ 'stroke-width': linewidth,
1879
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
1880
+ }
1881
+ });
1882
+
1883
+ // Draw the cap to the LOWER line
1884
+ var errorbarCap = RGraph.SVG.create({
1885
+ svg: this.svg,
1886
+ type: 'line',
1887
+ parent: opt.parent,
1888
+ attr: {
1889
+ x1: opt.x - halfCapWidth,
1890
+ y1: y2,
1891
+ x2: opt.x + halfCapWidth,
1892
+ y2: y2,
1893
+ stroke: color,
1894
+ 'stroke-width': linewidth,
1895
+ 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
1896
+ }
1897
+ });
1898
+ }
1899
+ };
1900
+
1901
+
1902
+
1903
+
1904
+
1905
+
1906
+
1907
+
1908
+ //
1909
+ // A worker function that handles Bar chart specific tooltip substitutions
1910
+ //
1911
+ this.tooltipSubstitutions = function (opt)
1912
+ {
1913
+ var indexes = RGraph.SVG.sequentialIndexToGrouped(opt.index, this.data),
1914
+ dataset = indexes[0],
1915
+ index = indexes[1];
1916
+
1917
+ return {
1918
+ index: index,
1919
+ dataset: dataset,
1920
+ sequentialIndex: opt.index,
1921
+ value: this.data[dataset][index].y,
1922
+ values: [this.data[dataset][index].y]
1923
+ };
1924
+ };
1925
+
1926
+
1927
+
1928
+
1929
+
1930
+
1931
+
1932
+
1933
+ //
1934
+ // A worker function that returns the correct color/label/value
1935
+ //
1936
+ // @param object specific The indexes that are applicable
1937
+ // @param number index The appropriate index
1938
+ //
1939
+ this.tooltipsFormattedCustom = function (specific, index, colors)
1940
+ {
1941
+ var color = this.data[specific.dataset][specific.index].color
1942
+ ? this.data[specific.dataset][specific.index].color
1943
+ : properties.colorsDefault;
1944
+ if (properties.tooltipsFormattedKeyColors && properties.tooltipsFormattedKeyColors[specific.dataset]) {
1945
+ color = properties.tooltipsFormattedKeyColors[specific.dataset];
1946
+ }
1947
+
1948
+ var label = properties.tooltipsFormattedKeyLabels[specific.dataset]
1949
+ ? properties.tooltipsFormattedKeyLabels[specific.dataset]
1950
+ : '';
1951
+
1952
+ return {
1953
+ label: label,
1954
+ color: color
1955
+ };
1956
+ };
1957
+
1958
+
1959
+
1960
+
1961
+
1962
+
1963
+
1964
+
1965
+ //
1966
+ // This allows for static tooltip positioning
1967
+ //
1968
+ this.positionTooltipStatic = function (args)
1969
+ {
1970
+ var obj = args.object,
1971
+ e = args.event,
1972
+ tooltip = args.tooltip,
1973
+ index = args.index,
1974
+ svgXY = RGraph.SVG.getSVGXY(obj.svg),
1975
+ coords = this.coords[args.index];
1976
+
1977
+ // Position the tooltip in the X direction
1978
+ args.tooltip.style.left = (
1979
+ svgXY[0] // The X coordinate of the SVG tag
1980
+ + coords.x // The X coordinate of the bar on the chart
1981
+ - (tooltip.offsetWidth / 2) // Subtract half of the tooltip width
1982
+ ) + 'px';
1983
+
1984
+ args.tooltip.style.top = (
1985
+ svgXY[1] // The Y coordinate of the SVG tag
1986
+ + coords.y // The Y coordinate of the bar on the chart
1987
+ - tooltip.offsetHeight // The height of the tooltip
1988
+ - 15 // An arbitrary amount
1989
+ ) + 'px';
1990
+ };
1991
+
1992
+
1993
+
1994
+
1995
+
1996
+
1997
+
1998
+
1999
+ //
2000
+ // A trace effect
2001
+ //
2002
+ // @param object Options to give to the effect
2003
+ // @param function A function to call when the effect has completed
2004
+ //
2005
+ this.trace = function ()
2006
+ {
2007
+ var opt = arguments[0] || {},
2008
+ frame = 1,
2009
+ frames = opt.frames || 60,
2010
+ obj = this;
2011
+
2012
+ this.isTrace = true;
2013
+
2014
+ this.draw();
2015
+
2016
+
2017
+
2018
+ // Create the clip area
2019
+ var clippath = RGraph.SVG.create({
2020
+ svg: this.svg,
2021
+ parent: this.svg.defs,
2022
+ type: 'clipPath',
2023
+ attr: {
2024
+ id: 'trace-effect-clip'
2025
+ }
2026
+ });
2027
+
2028
+ var clippathrect = RGraph.SVG.create({
2029
+ svg: this.svg,
2030
+ parent: clippath,
2031
+ type: 'rect',
2032
+ attr: {
2033
+ x: 0,
2034
+ y: 0,
2035
+ width: 0,
2036
+ height: this.height
2037
+ }
2038
+ });
2039
+
2040
+
2041
+
2042
+ var iterator = function ()
2043
+ {
2044
+ var width = (frame++) / frames * obj.width;
2045
+
2046
+ clippathrect.setAttribute("width", width);
2047
+
2048
+ if (frame <= frames) {
2049
+ RGraph.SVG.FX.update(iterator);
2050
+ } else {
2051
+
2052
+ // Remove the clippath
2053
+ clippath.parentNode.removeChild(clippath);
2054
+
2055
+ if (opt.callback) {
2056
+ (opt.callback)(obj);
2057
+ }
2058
+ }
2059
+ };
2060
+
2061
+ iterator();
2062
+
2063
+ return this;
2064
+ };
2065
+
2066
+
2067
+
2068
+
2069
+
2070
+
2071
+
2072
+
2073
+ //
2074
+ // Draws a trendline on the Scatter chart. This is also known
2075
+ // as a "best-fit line"
2076
+ //
2077
+ // @param dataset The index of the dataset to use
2078
+ //
2079
+ this.drawTrendline = function (dataset)
2080
+ {
2081
+ var colors = properties.trendlineColors,
2082
+ linewidth = properties.trendlineLinewidth,
2083
+ margin = properties.trendlineMargin;
2084
+
2085
+ // Allow for trendlineColor as well (note - no "s")
2086
+ if (RGraph.SVG.isString(properties.trendlineColor)) {
2087
+ colors = [properties.trendlineColor];
2088
+ }
2089
+
2090
+ // handle the options being arrays
2091
+ if (typeof colors === 'object' && colors[dataset]) {
2092
+ color = colors[dataset];
2093
+ } else if (typeof color === 'object') {
2094
+ color = 'gray';
2095
+ }
2096
+
2097
+ if (typeof linewidth === 'object' && typeof linewidth[dataset] === 'number') {
2098
+ linewidth = linewidth[dataset];
2099
+ } else if (typeof linewidth === 'object') {
2100
+ linewidth = 1;
2101
+ }
2102
+
2103
+ if (typeof margin === 'object' && typeof margin[dataset] === 'number') {
2104
+ margin = margin[dataset];
2105
+ } else if (typeof margin === 'object'){
2106
+ margin = 25;
2107
+ } else {
2108
+ margin = 0;
2109
+ }
2110
+
2111
+
2112
+ // Step 1: Calculate the mean values of the X coords and the Y coords
2113
+ for (var i=0,totalX=0,totalY=0; i<this.data[dataset].length; ++i) {
2114
+ totalX += this.data[dataset][i].x;
2115
+ totalY += this.data[dataset][i].y;
2116
+ }
2117
+
2118
+ var averageX = totalX / this.data[dataset].length;
2119
+ var averageY = totalY / this.data[dataset].length;
2120
+
2121
+ // Step 2: Calculate the slope of the line
2122
+
2123
+ // a: The X/Y values minus the average X/Y value
2124
+ for (var i=0,xCoordMinusAverageX=[],yCoordMinusAverageY=[],valuesMultiplied=[],xCoordMinusAverageSquared=[]; i<this.data[dataset].length; ++i) {
2125
+ xCoordMinusAverageX[i] = this.data[dataset][i].x - averageX;
2126
+ yCoordMinusAverageY[i] = this.data[dataset][i].y - averageY;
2127
+
2128
+ // b. Multiply the averages
2129
+ valuesMultiplied[i] = xCoordMinusAverageX[i] * yCoordMinusAverageY[i];
2130
+ xCoordMinusAverageSquared[i] = xCoordMinusAverageX[i] * xCoordMinusAverageX[i];
2131
+ }
2132
+
2133
+ var sumOfValuesMultiplied = RGraph.SVG.arraySum(valuesMultiplied);
2134
+ var sumOfXCoordMinusAverageSquared = RGraph.SVG.arraySum(xCoordMinusAverageSquared);
2135
+
2136
+ // Calculate m (???)
2137
+ var m = sumOfValuesMultiplied / sumOfXCoordMinusAverageSquared;
2138
+ var b = averageY - (m * averageX);
2139
+
2140
+ // y = mx + b
2141
+
2142
+ coords = [
2143
+ [properties.xaxisScaleMin, m * properties.xaxisScaleMin + b],
2144
+ [properties.xaxisScaleMax, m * properties.xaxisScaleMax + b]
2145
+ ];
2146
+
2147
+ //
2148
+ // Draw the line
2149
+ //
2150
+
2151
+ // Set dotted, dash or a custom dash array
2152
+ var strokeDasharray = ''
2153
+
2154
+ if (properties.trendlineDashed) {
2155
+ strokeDasharray = '4,4';
2156
+
2157
+ }
2158
+
2159
+ if (properties.trendlineDotted) {
2160
+ strokeDasharray = '1, 4';
2161
+ }
2162
+
2163
+ if (!RGraph.SVG.isNull(properties.trendlineDashArray) && typeof properties.trendlineDashArray === 'object') {
2164
+ strokeDasharray = String(properties.trendlineDashArray).replace(/[|]/, '');
2165
+ }
2166
+
2167
+
2168
+ // Clip the canvas again so that the line doesn't look overly long
2169
+ // (use the minimum an maximum points for this)
2170
+ for (var i=0,xValues=[],yValues=[]; i<this.data[dataset].length; ++i) {
2171
+ if (typeof this.data[dataset][i].x === 'number') {
2172
+ xValues.push(this.data[dataset][i].x);
2173
+ }
2174
+
2175
+ if (typeof this.data[dataset][i].y === 'number') {
2176
+ yValues.push(this.data[dataset][i].y);
2177
+ }
2178
+ }
2179
+
2180
+ // These are the minimum and maximum X/Y values for this dataset
2181
+ var x1 = RGraph.SVG.arrayMin(xValues);
2182
+ var y1 = RGraph.SVG.arrayMin(yValues);
2183
+ var x2 = RGraph.SVG.arrayMax(xValues);
2184
+ var y2 = RGraph.SVG.arrayMax(yValues);
2185
+
2186
+
2187
+ // Convert the X/Y values into coordinates on the canvas
2188
+ x1 = this.getXCoord(x1);
2189
+ y1 = this.getYCoord(y1, properties.outofbounds);
2190
+ x2 = this.getXCoord(x2);
2191
+ y2 = this.getYCoord(y2, properties.outofbounds);
2192
+
2193
+
2194
+
2195
+
2196
+
2197
+
2198
+
2199
+
2200
+ // Create the SVG clipPath region
2201
+ var clippath = RGraph.SVG.create({
2202
+ svg: this.svg,
2203
+ parent: this.svg.defs,
2204
+ type: 'clipPath',
2205
+ attr: {
2206
+ id: 'trendline-clippath-dataset-' + dataset
2207
+ }
2208
+ });
2209
+
2210
+
2211
+ RGraph.SVG.create({
2212
+ svg: this.svg,
2213
+ parent: clippath,
2214
+ type: 'rect',
2215
+ attr: {
2216
+ x: properties.trendlineClipping === false ? properties.marginLeft : x1 - margin,
2217
+ y: properties.trendlineClipping === false ? properties.marginTop : y2 - margin,
2218
+ width: properties.trendlineClipping === false ?
2219
+ (this.width - properties.marginLeft - properties.marginRight) :
2220
+ x2 - x1 + margin + margin,
2221
+ height: properties.trendlineClipping === false ?
2222
+ this.height - properties.marginTop - properties.marginBottom:
2223
+ y1 - y2 + margin + margin
2224
+ }
2225
+ });
2226
+
2227
+
2228
+
2229
+
2230
+
2231
+
2232
+
2233
+
2234
+ var line = RGraph.SVG.create({
2235
+ svg: this.svg,
2236
+ parent: this.svg.all,
2237
+ type: 'path',
2238
+ attr: {
2239
+ d: 'M{1} {2} L{3} {4}'.format(
2240
+ this.getXCoord(coords[0][0]),
2241
+ this.getYCoord(coords[0][1]),
2242
+ this.getXCoord(coords[1][0]),
2243
+ this.getYCoord(coords[1][1])
2244
+ ),
2245
+ stroke: color,
2246
+ fill:'none',
2247
+ 'stroke-width': linewidth,
2248
+ 'stroke-dasharray': strokeDasharray,
2249
+ 'stroke-linecap': 'round',
2250
+
2251
+ // Makes trendline clipping redundant in favour
2252
+ // of the trace effect
2253
+ //'clip-path': 'url(#trendline-clippath-dataset-' + dataset + ')'
2254
+ //
2255
+ 'clip-path': 'url(#trace-effect-clip)'
2256
+ }
2257
+ });
2258
+ };
2259
+
2260
+
2261
+
2262
+
2263
+
2264
+
2265
+
2266
+
2267
+ return this;
2268
+ };
2269
+
2270
+
2271
+
2272
+
2273
+
2274
+
2275
+
2276
+
2277
+
2278
+
2279
+
2280
+ // End module pattern
2281
+ })(window, document);