highcharts-rails 3.0.1.5 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v3.0.1 (2013-04-09)
2
+ * @license Highcharts JS v3.0.2 (2013-06-05)
3
3
  * MooTools adapter
4
4
  *
5
5
  * (c) 2010-2013 Torstein Hønsi
@@ -187,7 +187,7 @@ win.HighchartsAdapter = {
187
187
  * Return the index of an item in an array, or -1 if not matched
188
188
  */
189
189
  inArray: function (item, arr, from) {
190
- return arr.indexOf(item, from);
190
+ return arr ? arr.indexOf(item, from) : -1;
191
191
  },
192
192
 
193
193
  /**
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v3.0.1 (2013-04-09)
2
+ * @license Highcharts JS v3.0.2 (2013-06-05)
3
3
  * Prototype adapter
4
4
  *
5
5
  * @author Michael Nelson, Torstein Hønsi.
@@ -206,8 +206,8 @@ return {
206
206
  $A(arr).each(fn);
207
207
  },
208
208
 
209
- inArray: function (item, arr) {
210
- return arr.indexOf(item);
209
+ inArray: function (item, arr, from) {
210
+ return arr ? arr.indexOf(item, from) : -1;
211
211
  },
212
212
 
213
213
  /**
@@ -1,50 +1,2525 @@
1
- /*
2
- Highcharts JS v3.0.1 (2013-04-09)
3
-
4
- (c) 2009-2013 Torstein Hønsi
5
-
6
- License: www.highcharts.com/license
7
- */
8
- (function(m,F){function K(a,b,c){this.init.call(this,a,b,c)}function L(a,b,c){a.call(this,b,c);if(this.chart.polar)this.closeSegment=function(a){var c=this.xAxis.center;a.push("L",c[0],c[1])},this.closedStacks=!0}function M(a,b){var c=this.chart,d=this.options.animation,e=this.group,g=this.markerGroup,f=this.xAxis.center,k=c.plotLeft,l=c.plotTop;if(c.polar){if(c.renderer.isSVG)if(d===!0&&(d={}),b){if(c={translateX:f[0]+k,translateY:f[1]+l,scaleX:0.001,scaleY:0.001},e.attr(c),g)g.attrSetters=e.attrSetters,
9
- g.attr(c)}else c={translateX:k,translateY:l,scaleX:1,scaleY:1},e.animate(c,d),g&&g.animate(c,d),this.animate=null}else a.call(this,b)}var Q=m.arrayMin,R=m.arrayMax,s=m.each,H=m.extend,p=m.merge,S=m.map,r=m.pick,u=m.pInt,n=m.getOptions().plotOptions,h=m.seriesTypes,A=m.extendClass,N=m.splat,o=m.wrap,O=m.Axis,B=m.Tick,z=m.Series,q=h.column.prototype,v=Math,I=v.round,C=v.floor,J=v.ceil,T=v.min,U=v.max,w=function(){};H(K.prototype,{init:function(a,b,c){var d=this,e=d.defaultOptions;d.chart=b;if(b.angular)e.background=
10
- {};d.options=a=p(e,a);(a=a.background)&&s([].concat(N(a)).reverse(),function(a){var b=a.backgroundColor,a=p(d.defaultBackgroundOptions,a);if(b)a.backgroundColor=b;a.color=a.backgroundColor;c.options.plotBands.unshift(a)})},defaultOptions:{center:["50%","50%"],size:"85%",startAngle:0},defaultBackgroundOptions:{shape:"circle",borderWidth:1,borderColor:"silver",backgroundColor:{linearGradient:{x1:0,y1:0,x2:0,y2:1},stops:[[0,"#FFF"],[1,"#DDD"]]},from:Number.MIN_VALUE,innerRadius:0,to:Number.MAX_VALUE,
11
- outerRadius:"105%"}});var G=O.prototype,B=B.prototype,V={getOffset:w,redraw:function(){this.isDirty=!1},render:function(){this.isDirty=!1},setScale:w,setCategories:w,setTitle:w},P={isRadial:!0,defaultRadialGaugeOptions:{labels:{align:"center",x:0,y:null},minorGridLineWidth:0,minorTickInterval:"auto",minorTickLength:10,minorTickPosition:"inside",minorTickWidth:1,plotBands:[],tickLength:10,tickPosition:"inside",tickWidth:2,title:{rotation:0},zIndex:2},defaultRadialXOptions:{gridLineWidth:1,labels:{align:null,
12
- distance:15,x:0,y:null},maxPadding:0,minPadding:0,plotBands:[],showLastLabel:!1,tickLength:0},defaultRadialYOptions:{gridLineInterpolation:"circle",labels:{align:"right",x:-3,y:-2},plotBands:[],showLastLabel:!1,title:{x:4,text:null,rotation:90}},setOptions:function(a){this.options=p(this.defaultOptions,this.defaultRadialOptions,a)},getOffset:function(){G.getOffset.call(this);this.chart.axisOffset[this.side]=0;this.center=this.pane.center=h.pie.prototype.getCenter.call(this.pane)},getLinePath:function(a,
13
- b){var c=this.center,b=r(b,c[2]/2-this.offset);return this.chart.renderer.symbols.arc(this.left+c[0],this.top+c[1],b,b,{start:this.startAngleRad,end:this.endAngleRad,open:!0,innerR:0})},setAxisTranslation:function(){G.setAxisTranslation.call(this);if(this.center&&(this.transA=this.isCircular?(this.endAngleRad-this.startAngleRad)/(this.max-this.min||1):this.center[2]/2/(this.max-this.min||1),this.isXAxis))this.minPixelPadding=this.transA*this.minPointOffset+(this.reversed?(this.endAngleRad-this.startAngleRad)/
14
- 4:0)},beforeSetTickPositions:function(){this.autoConnect&&(this.max+=this.categories&&1||this.pointRange||this.closestPointRange)},setAxisSize:function(){G.setAxisSize.call(this);if(this.center)this.len=this.width=this.height=this.isCircular?this.center[2]*(this.endAngleRad-this.startAngleRad)/2:this.center[2]/2},getPosition:function(a,b){if(!this.isCircular)b=this.translate(a),a=this.min;return this.postTranslate(this.translate(a),r(b,this.center[2]/2)-this.offset)},postTranslate:function(a,b){var c=
15
- this.chart,d=this.center,a=this.startAngleRad+a;return{x:c.plotLeft+d[0]+Math.cos(a)*b,y:c.plotTop+d[1]+Math.sin(a)*b}},getPlotBandPath:function(a,b,c){var d=this.center,e=this.startAngleRad,g=d[2]/2,f=[r(c.outerRadius,"100%"),c.innerRadius,r(c.thickness,10)],k=/%$/,l,j=this.isCircular;this.options.gridLineInterpolation==="polygon"?d=this.getPlotLinePath(a).concat(this.getPlotLinePath(b,!0)):(j||(f[0]=this.translate(a),f[1]=this.translate(b)),f=S(f,function(a){k.test(a)&&(a=u(a,10)*g/100);return a}),
16
- c.shape==="circle"||!j?(a=-Math.PI/2,b=Math.PI*1.5,l=!0):(a=e+this.translate(a),b=e+this.translate(b)),d=this.chart.renderer.symbols.arc(this.left+d[0],this.top+d[1],f[0],f[0],{start:a,end:b,innerR:r(f[1],f[0]-f[2]),open:l}));return d},getPlotLinePath:function(a,b){var c=this.center,d=this.chart,e=this.getPosition(a),g,f,k;this.isCircular?k=["M",c[0]+d.plotLeft,c[1]+d.plotTop,"L",e.x,e.y]:this.options.gridLineInterpolation==="circle"?(a=this.translate(a))&&(k=this.getLinePath(0,a)):(g=d.xAxis[0],
17
- k=[],a=this.translate(a),c=g.tickPositions,g.autoConnect&&(c=c.concat([c[0]])),b&&(c=[].concat(c).reverse()),s(c,function(c,b){f=g.getPosition(c,a);k.push(b?"L":"M",f.x,f.y)}));return k},getTitlePosition:function(){var a=this.center,b=this.chart,c=this.options.title;return{x:b.plotLeft+a[0]+(c.x||0),y:b.plotTop+a[1]-{high:0.5,middle:0.25,low:0}[c.align]*a[2]+(c.y||0)}}};o(G,"init",function(a,b,c){var i;var d=b.angular,e=b.polar,g=c.isX,f=d&&g,k,l;l=b.options;var j=c.pane||0;if(d){if(H(this,f?V:P),
18
- k=!g)this.defaultRadialOptions=this.defaultRadialGaugeOptions}else if(e)H(this,P),this.defaultRadialOptions=(k=g)?this.defaultRadialXOptions:p(this.defaultYAxisOptions,this.defaultRadialYOptions);a.call(this,b,c);if(!f&&(d||e)){a=this.options;if(!b.panes)b.panes=[];this.pane=(i=b.panes[j]=b.panes[j]||new K(N(l.pane)[j],b,this),j=i);j=j.options;b.inverted=!1;l.chart.zoomType=null;this.startAngleRad=b=(j.startAngle-90)*Math.PI/180;this.endAngleRad=l=(r(j.endAngle,j.startAngle+360)-90)*Math.PI/180;this.offset=
19
- a.offset||0;if((this.isCircular=k)&&c.max===F&&l-b===2*Math.PI)this.autoConnect=!0}});o(B,"getPosition",function(a,b,c,d,e){var g=this.axis;return g.getPosition?g.getPosition(c):a.call(this,b,c,d,e)});o(B,"getLabelPosition",function(a,b,c,d,e,g,f,k,l){var j=this.axis,i=g.y,h=g.align,y=(j.translate(this.pos)+j.startAngleRad+Math.PI/2)/Math.PI*180;j.isRadial?(a=j.getPosition(this.pos,j.center[2]/2+r(g.distance,-25)),g.rotation==="auto"?d.attr({rotation:y}):i===null&&(i=u(d.styles.lineHeight)*0.9-d.getBBox().height/
20
- 2),h===null&&(h=j.isCircular?y>20&&y<160?"left":y>200&&y<340?"right":"center":"center",d.attr({align:h})),a.x+=g.x,a.y+=i):a=a.call(this,b,c,d,e,g,f,k,l);return a});o(B,"getMarkPath",function(a,b,c,d,e,g,f){var k=this.axis;k.isRadial?(a=k.getPosition(this.pos,k.center[2]/2+d),b=["M",b,c,"L",a.x,a.y]):b=a.call(this,b,c,d,e,g,f);return b});n.arearange=p(n.area,{lineWidth:1,marker:null,threshold:null,tooltip:{pointFormat:'<span style="color:{series.color}">{series.name}</span>: <b>{point.low}</b> - <b>{point.high}</b><br/>'},
21
- trackByArea:!0,dataLabels:{verticalAlign:null,xLow:0,xHigh:0,yLow:0,yHigh:0}});h.arearange=m.extendClass(h.area,{type:"arearange",pointArrayMap:["low","high"],toYData:function(a){return[a.low,a.high]},pointValKey:"low",translate:function(){var a=this.yAxis;h.area.prototype.translate.apply(this);s(this.points,function(b){if(b.y!==null)b.plotLow=b.plotY,b.plotHigh=a.translate(b.high,0,1,0,1)})},getSegmentPath:function(a){var b=[],c=a.length,d=z.prototype.getSegmentPath,e,g;g=this.options;for(var f=
22
- g.step;c--;)e=a[c],b.push({plotX:e.plotX,plotY:e.plotHigh});a=d.call(this,a);if(f)f===!0&&(f="left"),g.step={left:"right",center:"center",right:"left"}[f];b=d.call(this,b);g.step=f;g=[].concat(a,b);b[0]="L";this.areaPath=this.areaPath.concat(a,b);return g},drawDataLabels:function(){var a=this.data,b=a.length,c,d=[],e=z.prototype,g=this.options.dataLabels,f,k=this.chart.inverted;if(g.enabled||this._hasPointLabels){for(c=b;c--;)f=a[c],f.y=f.high,f.plotY=f.plotHigh,d[c]=f.dataLabel,f.dataLabel=f.dataLabelUpper,
23
- f.below=!1,k?(g.align="left",g.x=g.xHigh):g.y=g.yHigh;e.drawDataLabels.apply(this,arguments);for(c=b;c--;)f=a[c],f.dataLabelUpper=f.dataLabel,f.dataLabel=d[c],f.y=f.low,f.plotY=f.plotLow,f.below=!0,k?(g.align="right",g.x=g.xLow):g.y=g.yLow;e.drawDataLabels.apply(this,arguments)}},alignDataLabel:h.column.prototype.alignDataLabel,getSymbol:h.column.prototype.getSymbol,drawPoints:w});n.areasplinerange=p(n.arearange);h.areasplinerange=A(h.arearange,{type:"areasplinerange",getPointSpline:h.spline.prototype.getPointSpline});
24
- n.columnrange=p(n.column,n.arearange,{lineWidth:1,pointRange:null});h.columnrange=A(h.arearange,{type:"columnrange",translate:function(){var a=this.yAxis,b;q.translate.apply(this);s(this.points,function(c){var d=c.shapeArgs;c.plotHigh=b=a.translate(c.high,0,1,0,1);c.plotLow=c.plotY;d.y=b;d.height=c.plotY-b})},trackerGroups:["group","dataLabels"],drawGraph:w,pointAttrToOptions:q.pointAttrToOptions,drawPoints:q.drawPoints,drawTracker:q.drawTracker,animate:q.animate,getColumnMetrics:q.getColumnMetrics});
25
- n.gauge=p(n.line,{dataLabels:{enabled:!0,y:15,borderWidth:1,borderColor:"silver",borderRadius:3,style:{fontWeight:"bold"},verticalAlign:"top",zIndex:2},dial:{},pivot:{},tooltip:{headerFormat:""},showInLegend:!1});B={type:"gauge",pointClass:m.extendClass(m.Point,{setState:function(a){this.state=a}}),angular:!0,drawGraph:w,trackerGroups:["group","dataLabels"],translate:function(){var a=this.yAxis,b=this.options,c=a.center;this.generatePoints();s(this.points,function(d){var e=p(b.dial,d.dial),g=u(r(e.radius,
26
- 80))*c[2]/200,f=u(r(e.baseLength,70))*g/100,k=u(r(e.rearLength,10))*g/100,l=e.baseWidth||3,j=e.topWidth||1,i=a.startAngleRad+a.translate(d.y,null,null,null,!0);b.wrap===!1&&(i=Math.max(a.startAngleRad,Math.min(a.endAngleRad,i)));i=i*180/Math.PI;d.shapeType="path";d.shapeArgs={d:e.path||["M",-k,-l/2,"L",f,-l/2,g,-j/2,g,j/2,f,l/2,-k,l/2,"z"],translateX:c[0],translateY:c[1],rotation:i};d.plotX=c[0];d.plotY=c[1]})},drawPoints:function(){var a=this,b=a.yAxis.center,c=a.pivot,d=a.options,e=d.pivot,g=a.chart.renderer;
27
- s(a.points,function(c){var b=c.graphic,e=c.shapeArgs,j=e.d,i=p(d.dial,c.dial);b?(b.animate(e),e.d=j):c.graphic=g[c.shapeType](e).attr({stroke:i.borderColor||"none","stroke-width":i.borderWidth||0,fill:i.backgroundColor||"black",rotation:e.rotation}).add(a.group)});c?c.animate({translateX:b[0],translateY:b[1]}):a.pivot=g.circle(0,0,r(e.radius,5)).attr({"stroke-width":e.borderWidth||0,stroke:e.borderColor||"silver",fill:e.backgroundColor||"black"}).translate(b[0],b[1]).add(a.group)},animate:function(a){var b=
28
- this;if(!a)s(b.points,function(a){var d=a.graphic;d&&(d.attr({rotation:b.yAxis.startAngleRad*180/Math.PI}),d.animate({rotation:a.shapeArgs.rotation},b.options.animation))}),b.animate=null},render:function(){this.group=this.plotGroup("group","series",this.visible?"visible":"hidden",this.options.zIndex,this.chart.seriesGroup);h.pie.prototype.render.call(this);this.group.clip(this.chart.clipRect)},setData:h.pie.prototype.setData,drawTracker:h.column.prototype.drawTracker};h.gauge=m.extendClass(h.line,
29
- B);n.boxplot=p(n.column,{fillColor:"#FFFFFF",lineWidth:1,medianWidth:2,states:{hover:{brightness:-0.3}},threshold:null,tooltip:{pointFormat:'<span style="color:{series.color};font-weight:bold">{series.name}</span><br/>Minimum: {point.low}<br/>Lower quartile: {point.q1}<br/>Median: {point.median}<br/>Higher quartile: {point.q3}<br/>Maximum: {point.high}<br/>'},whiskerLength:"50%",whiskerWidth:2});h.boxplot=A(h.column,{type:"boxplot",pointArrayMap:["low","q1","median","q3","high"],toYData:function(a){return[a.low,
30
- a.q1,a.median,a.q3,a.high]},pointValKey:"high",pointAttrToOptions:{fill:"fillColor",stroke:"color","stroke-width":"lineWidth"},drawDataLabels:w,translate:function(){var a=this.yAxis,b=this.pointArrayMap;h.column.prototype.translate.apply(this);s(this.points,function(c){s(b,function(b){c[b]!==null&&(c[b+"Plot"]=a.translate(c[b],0,1,0,1))})})},drawPoints:function(){var a=this,b=a.points,c=a.options,d=a.chart.renderer,e,g,f,k,l,j,i,h,y,m,t,n,r,x,o,p,v,q,w,u,B,A,z=a.doQuartiles!==!1,D=parseInt(a.options.whiskerLength,
31
- 10)/100;s(b,function(b){y=b.graphic;B=b.shapeArgs;t={};x={};p={};A=b.color||a.color;if(b.plotY!==F)if(e=b.pointAttr[b.selected?"selected":""],v=B.width,q=C(B.x),w=q+v,u=I(v/2),g=C(z?b.q1Plot:b.lowPlot),f=C(z?b.q3Plot:b.lowPlot),k=C(b.highPlot),l=C(b.lowPlot),t.stroke=b.stemColor||c.stemColor||A,t["stroke-width"]=b.stemWidth||c.stemWidth||c.lineWidth,t.dashstyle=b.stemDashStyle||c.stemDashStyle,x.stroke=b.whiskerColor||c.whiskerColor||A,x["stroke-width"]=b.whiskerWidth||c.whiskerWidth||c.lineWidth,
32
- p.stroke=b.medianColor||c.medianColor||A,p["stroke-width"]=b.medianWidth||c.medianWidth||c.lineWidth,i=t["stroke-width"]%2/2,h=q+u+i,m=["M",h,f,"L",h,k,"M",h,g,"L",h,l,"z"],z&&(i=e["stroke-width"]%2/2,h=C(h)+i,g=C(g)+i,f=C(f)+i,q+=i,w+=i,n=["M",q,f,"L",q,g,"L",w,g,"L",w,f,"L",q,f,"z"]),D&&(i=x["stroke-width"]%2/2,k+=i,l+=i,r=["M",h-u*D,k,"L",h+u*D,k,"M",h-u*D,l,"L",h+u*D,l]),i=p["stroke-width"]%2/2,j=I(b.medianPlot)+i,o=["M",q,j,"L",w,j,"z"],y)b.stem.animate({d:m}),D&&b.whiskers.animate({d:r}),z&&
33
- b.box.animate({d:n}),b.medianShape.animate({d:o});else{b.graphic=y=d.g().add(a.group);b.stem=d.path(m).attr(t).add(y);if(D)b.whiskers=d.path(r).attr(x).add(y);if(z)b.box=d.path(n).attr(e).add(y);b.medianShape=d.path(o).attr(p).add(y)}})}});n.errorbar=p(n.boxplot,{color:"#000000",grouping:!1,linkedTo:":previous",tooltip:{pointFormat:n.arearange.tooltip.pointFormat},whiskerWidth:null});h.errorbar=A(h.boxplot,{type:"errorbar",pointArrayMap:["low","high"],toYData:function(a){return[a.low,a.high]},pointValKey:"high",
34
- doQuartiles:!1,getColumnMetrics:function(){return this.linkedParent&&this.linkedParent.columnMetrics||h.column.prototype.getColumnMetrics.call(this)}});o(G,"getSeriesExtremes",function(a,b){a.call(this,b);if(!this.isXAxis){var c=this,d=[],e=!0;s(c.series,function(a){if(a.visible&&a.stackKey&&!(a.type!=="waterfall"||HighchartsAdapter.inArray(a.stackKey)!==-1)){if(e)c.dataMin=c.dataMax=null,e=!1;var b=a.processedYData,k=b.length,h=b[0],j=b[0],i=a.options.threshold,m=c.stacks,n=a.stackKey,p="-"+n,t,
35
- o,q,x;for(x=0;x<k;x++){q=b[x]<i?p:n;t=m[q][x].total;if(x>i)t+=o,m[q][x].setTotal(t),m[q][x]._cum=null;t<h&&(h=t);t>j&&(j=t);o=t}a.dataMin=h;a.dataMax=j;c.dataMin=T(r(c.dataMin,h),h,i);c.dataMax=U(r(c.dataMax,j),j,i);d.push(a.stackKey);if(typeof i==="number")if(c.dataMin>=i)c.dataMin=i,c.ignoreMinPadding=!0;else if(c.dataMax<i)c.dataMax=i,c.ignoreMaxPadding=!0}})}});n.waterfall=p(n.column,{lineWidth:1,lineColor:"#333",dashStyle:"dot",borderColor:"#333"});h.waterfall=A(h.column,{type:"waterfall",upColorProp:"fill",
36
- pointArrayMap:["y","low"],pointValKey:"y",init:function(a,b){b.stacking=!0;h.column.prototype.init.call(this,a,b)},translate:function(){var a=this.yAxis,b,c,d,e,g,f,k,l,j,i,m,n,o=this.options.borderWidth%2/2;h.column.prototype.translate.apply(this);d=this.points;j=k=d[0];f=l=d[0].y;for(c=1,b=d.length;c<b;c++)e=d[c],g=e.shapeArgs,i=this.getStack(c),m=this.getStack(c-1),n=this.getStackY(m),j===null&&(j=e,l=0),e.y&&!e.isSum&&!e.isIntermediateSum&&(f+=e.y,l+=e.y),e.isSum||e.isIntermediateSum?(e.isIntermediateSum?
37
- (i=this.getSumEdges(j,d[c-1]),e.y=l,j=null):(i=this.getSumEdges(k,d[c-1]),e.y=f),g.y=e.plotY=i[1],g.height=i[0]-i[1]):e.y<0?(m=i._cum===null?m.total:i._cum,i._cum=m+e.y,e=J(a.translate(m,0,1))-o,i=a.translate(i._cum,0,1),g.y=e,g.height=J(i-e)):g.height=C(n-g.y)},processData:function(a){z.prototype.processData.call(this,a);var a=this.yData,b=a.length,c,d;for(d=0;d<b;d++)c=a[d],c!==null&&typeof c!=="number"&&(a[d]=c==="sum"?null:c==="intermediateSum"?null:c[0])},toYData:function(a){if(a.isSum)return"sum";
38
- else if(a.isIntermediateSum)return"intermediateSum";return[a.y]},getAttribs:function(){h.column.prototype.getAttribs.apply(this,arguments);var a=this.options,b=a.states,c=a.upColor||this.color,a=m.Color(c).brighten(0.1).get(),d=p(this.pointAttr),e=this.upColorProp;d[""][e]=c;d.hover[e]=b.hover.upColor||a;d.select[e]=b.select.upColor||c;s(this.points,function(a){if(a.y>0&&!a.color)a.pointAttr=d,a.color=c})},getGraphPath:function(){var a=this.data,b=a.length,c=I(this.options.lineWidth+this.options.borderWidth)%
39
- 2/2,d=[],e,g,f;for(f=1;f<b;f++)g=a[f].shapeArgs,e=a[f-1].shapeArgs,g=["M",e.x+e.width,e.y+c,"L",g.x,e.y+c],a[f-1].y<0&&(g[2]+=e.height,g[5]+=e.height),d=d.concat(g);return d},getStack:function(a){var b=this.yAxis.stacks,c=this.stackKey;this.processedYData[a]<this.options.threshold&&(c="-"+c);return b[c][a]},getStackY:function(a){return J(this.yAxis.translate(a.total,null,!0))},getSumEdges:function(a,b){var c,d,e;d=this.options.threshold;c=a.y>=d?a.shapeArgs.y+a.shapeArgs.height:a.shapeArgs.y;d=b.y>=
40
- d?b.shapeArgs.y:b.shapeArgs.y+b.shapeArgs.height;d>c&&(e=c,c=d,d=e);return[c,d]},drawGraph:z.prototype.drawGraph});n.bubble=p(n.scatter,{dataLabels:{inside:!0,style:{color:"white",textShadow:"0px 0px 3px black"},verticalAlign:"middle"},marker:{lineColor:null,lineWidth:1},minSize:8,maxSize:"20%",tooltip:{pointFormat:"({point.x}, {point.y}), Size: {point.z}"},zThreshold:0});h.bubble=A(h.scatter,{type:"bubble",pointArrayMap:["y","z"],trackerGroups:["group","dataLabelsGroup"],pointAttrToOptions:{stroke:"lineColor",
41
- "stroke-width":"lineWidth",fill:"fillColor"},applyOpacity:function(a){var b=this.options.marker,c=r(b.fillOpacity,0.5),a=a||b.fillColor||this.color;c!==1&&(a=m.Color(a).setOpacity(c).get("rgba"));return a},convertAttribs:function(){var a=z.prototype.convertAttribs.apply(this,arguments);a.fill=this.applyOpacity(a.fill);return a},getRadii:function(a,b,c,d){var e,g,f,k=this.zData,h=[];for(g=0,e=k.length;g<e;g++)f=b-a,f=f>0?(k[g]-a)/(b-a):0.5,h.push(v.round(c+f*(d-c))/2);this.radii=h},animate:function(a){var b=
42
- this.options.animation;if(!a)s(this.points,function(a){var d=a.graphic,a=a.shapeArgs;d&&a&&(d.attr("r",1),d.animate({r:a.r},b))}),this.animate=null},translate:function(){var a,b=this.data,c,d,e=this.radii;h.scatter.prototype.translate.call(this);for(a=b.length;a--;)c=b[a],d=e[a],c.negative=c.z<(this.options.zThreshold||0),d>=this.minPxSize/2?(c.shapeType="circle",c.shapeArgs={x:c.plotX,y:c.plotY,r:d},c.dlBox={x:c.plotX-d,y:c.plotY-d,width:2*d,height:2*d}):c.shapeArgs=c.plotY=c.dlBox=F},drawLegendSymbol:function(a,
43
- b){var c=u(a.itemStyle.fontSize)/2;b.legendSymbol=this.chart.renderer.circle(c,a.baseline-c,c).attr({zIndex:3}).add(b.legendGroup)},drawPoints:h.column.prototype.drawPoints,alignDataLabel:h.column.prototype.alignDataLabel});O.prototype.beforePadding=function(){var a=this.len,b=this.chart,c=0,d=a,e=this.isXAxis,g=e?"xData":"yData",f=this.min,k={},h=v.min(b.plotWidth,b.plotHeight),j=Number.MAX_VALUE,i=-Number.MAX_VALUE,m=this.max-f,n=a/m,o=[];this.allowZoomOutside=!0;this.tickPositions&&(s(this.series,
44
- function(a){var b=a.options;if(a.type==="bubble"&&a.visible&&(o.push(a),e))s(["minSize","maxSize"],function(a){var c=b[a],d=/%$/.test(c),c=u(c);k[a]=d?h*c/100:c}),a.minPxSize=k.minSize,a=a.zData,j=v.min(j,v.max(Q(a),b.displayNegative===!1?b.zThreshold:-Number.MAX_VALUE)),i=v.max(i,R(a))}),s(o,function(a){var b=a[g],h=b.length,l;e&&a.getRadii(j,i,k.minSize,k.maxSize);if(m>0)for(;h--;)l=a.radii[h],c=Math.min((b[h]-f)*n-l,c),d=Math.max((b[h]-f)*n+l,d)}),m>0&&r(this.options.min,this.userMin)===F&&r(this.options.max,
45
- this.userMax)===F&&(d-=a,n*=(a+c-d)/a,this.min+=c/n,this.max+=d/n))};var E=z.prototype,n=m.Pointer.prototype;E.toXY=function(a){var b,c=this.chart;b=a.plotX;var d=a.plotY;a.rectPlotX=b;a.rectPlotY=d;a.clientX=b/Math.PI*180;b=this.xAxis.postTranslate(a.plotX,this.yAxis.len-d);a.plotX=a.polarPlotX=b.x-c.plotLeft;a.plotY=a.polarPlotY=b.y-c.plotTop};o(h.area.prototype,"init",L);o(h.areaspline.prototype,"init",L);o(h.spline.prototype,"getPointSpline",function(a,b,c,d){var e,g,f,h,l,j,i;if(this.chart.polar){e=
46
- c.plotX;g=c.plotY;a=b[d-1];f=b[d+1];this.connectEnds&&(a||(a=b[b.length-2]),f||(f=b[1]));if(a&&f)h=a.plotX,l=a.plotY,b=f.plotX,j=f.plotY,h=(1.5*e+h)/2.5,l=(1.5*g+l)/2.5,f=(1.5*e+b)/2.5,i=(1.5*g+j)/2.5,b=Math.sqrt(Math.pow(h-e,2)+Math.pow(l-g,2)),j=Math.sqrt(Math.pow(f-e,2)+Math.pow(i-g,2)),h=Math.atan2(l-g,h-e),l=Math.atan2(i-g,f-e),i=Math.PI/2+(h+l)/2,Math.abs(h-i)>Math.PI/2&&(i-=Math.PI),h=e+Math.cos(i)*b,l=g+Math.sin(i)*b,f=e+Math.cos(Math.PI+i)*j,i=g+Math.sin(Math.PI+i)*j,c.rightContX=f,c.rightContY=
47
- i;d?(c=["C",a.rightContX||a.plotX,a.rightContY||a.plotY,h||e,l||g,e,g],a.rightContX=a.rightContY=null):c=["M",e,g]}else c=a.call(this,b,c,d);return c});o(E,"translate",function(a){a.call(this);if(this.chart.polar&&!this.preventPostTranslate)for(var a=this.points,b=a.length;b--;)this.toXY(a[b])});o(E,"getSegmentPath",function(a,b){var c=this.points;if(this.chart.polar&&this.options.connectEnds!==!1&&b[b.length-1]===c[c.length-1]&&c[0].y!==null)this.connectEnds=!0,b=[].concat(b,[c[0]]);return a.call(this,
48
- b)});o(E,"animate",M);o(q,"animate",M);o(E,"setTooltipPoints",function(a,b){this.chart.polar&&H(this.xAxis,{tooltipLen:360});return a.call(this,b)});o(q,"translate",function(a){var b=this.xAxis,c=this.yAxis.len,d=b.center,e=b.startAngleRad,g=this.chart.renderer,f,h;this.preventPostTranslate=!0;a.call(this);if(b.isRadial){b=this.points;for(h=b.length;h--;)f=b[h],a=f.barX+e,f.shapeType="path",f.shapeArgs={d:g.symbols.arc(d[0],d[1],c-f.plotY,null,{start:a,end:a+f.pointWidth,innerR:c-r(f.yBottom,c)})},
49
- this.toXY(f)}});o(q,"alignDataLabel",function(a,b,c,d,e,g){if(this.chart.polar){a=b.rectPlotX/Math.PI*180;if(d.align===null)d.align=a>20&&a<160?"left":a>200&&a<340?"right":"center";if(d.verticalAlign===null)d.verticalAlign=a<45||a>315?"bottom":a>135&&a<225?"top":"middle";E.alignDataLabel.call(this,b,c,d,e,g)}else a.call(this,b,c,d,e,g)});o(n,"getIndex",function(a,b){var c,d=this.chart,e;d.polar?(e=d.xAxis[0].center,c=b.chartX-e[0]-d.plotLeft,d=b.chartY-e[1]-d.plotTop,c=180-Math.round(Math.atan2(c,
50
- d)/Math.PI*180)):c=a.call(this,b);return c});o(n,"getCoordinates",function(a,b){var c=this.chart,d={xAxis:[],yAxis:[]};c.polar?s(c.axes,function(a){var g=a.isXAxis,f=a.center,h=b.chartX-f[0]-c.plotLeft,f=b.chartY-f[1]-c.plotTop;d[g?"xAxis":"yAxis"].push({axis:a,value:a.translate(g?Math.PI-Math.atan2(h,f):Math.sqrt(Math.pow(h,2)+Math.pow(f,2)),!0)})}):d=a.call(this,b);return d})})(Highcharts);
1
+ // ==ClosureCompiler==
2
+ // @compilation_level SIMPLE_OPTIMIZATIONS
3
+
4
+ /**
5
+ * @license Highcharts JS v3.0.2 (2013-06-05)
6
+ *
7
+ * (c) 2009-2013 Torstein Hønsi
8
+ *
9
+ * License: www.highcharts.com/license
10
+ */
11
+
12
+ // JSLint options:
13
+ /*global Highcharts, HighchartsAdapter, document, window, navigator, setInterval, clearInterval, clearTimeout, setTimeout, location, jQuery, $, console */
14
+
15
+ (function (Highcharts, UNDEFINED) {
16
+ var arrayMin = Highcharts.arrayMin,
17
+ arrayMax = Highcharts.arrayMax,
18
+ each = Highcharts.each,
19
+ extend = Highcharts.extend,
20
+ merge = Highcharts.merge,
21
+ map = Highcharts.map,
22
+ pick = Highcharts.pick,
23
+ pInt = Highcharts.pInt,
24
+ defaultPlotOptions = Highcharts.getOptions().plotOptions,
25
+ seriesTypes = Highcharts.seriesTypes,
26
+ extendClass = Highcharts.extendClass,
27
+ splat = Highcharts.splat,
28
+ wrap = Highcharts.wrap,
29
+ Axis = Highcharts.Axis,
30
+ Tick = Highcharts.Tick,
31
+ Series = Highcharts.Series,
32
+ colProto = seriesTypes.column.prototype,
33
+ math = Math,
34
+ mathRound = math.round,
35
+ mathFloor = math.floor,
36
+ mathCeil = math.ceil,
37
+ mathMin = math.min,
38
+ mathMax = math.max,
39
+ noop = function () {};/**
40
+ * The Pane object allows options that are common to a set of X and Y axes.
41
+ *
42
+ * In the future, this can be extended to basic Highcharts and Highstock.
43
+ */
44
+ function Pane(options, chart, firstAxis) {
45
+ this.init.call(this, options, chart, firstAxis);
46
+ }
47
+
48
+ // Extend the Pane prototype
49
+ extend(Pane.prototype, {
50
+
51
+ /**
52
+ * Initiate the Pane object
53
+ */
54
+ init: function (options, chart, firstAxis) {
55
+ var pane = this,
56
+ backgroundOption,
57
+ defaultOptions = pane.defaultOptions;
58
+
59
+ pane.chart = chart;
60
+
61
+ // Set options
62
+ if (chart.angular) { // gauges
63
+ defaultOptions.background = {}; // gets extended by this.defaultBackgroundOptions
64
+ }
65
+ pane.options = options = merge(defaultOptions, options);
66
+
67
+ backgroundOption = options.background;
68
+
69
+ // To avoid having weighty logic to place, update and remove the backgrounds,
70
+ // push them to the first axis' plot bands and borrow the existing logic there.
71
+ if (backgroundOption) {
72
+ each([].concat(splat(backgroundOption)).reverse(), function (config) {
73
+ var backgroundColor = config.backgroundColor; // if defined, replace the old one (specific for gradients)
74
+ config = merge(pane.defaultBackgroundOptions, config);
75
+ if (backgroundColor) {
76
+ config.backgroundColor = backgroundColor;
77
+ }
78
+ config.color = config.backgroundColor; // due to naming in plotBands
79
+ firstAxis.options.plotBands.unshift(config);
80
+ });
81
+ }
82
+ },
83
+
84
+ /**
85
+ * The default options object
86
+ */
87
+ defaultOptions: {
88
+ // background: {conditional},
89
+ center: ['50%', '50%'],
90
+ size: '85%',
91
+ startAngle: 0
92
+ //endAngle: startAngle + 360
93
+ },
94
+
95
+ /**
96
+ * The default background options
97
+ */
98
+ defaultBackgroundOptions: {
99
+ shape: 'circle',
100
+ borderWidth: 1,
101
+ borderColor: 'silver',
102
+ backgroundColor: {
103
+ linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
104
+ stops: [
105
+ [0, '#FFF'],
106
+ [1, '#DDD']
107
+ ]
108
+ },
109
+ from: Number.MIN_VALUE, // corrected to axis min
110
+ innerRadius: 0,
111
+ to: Number.MAX_VALUE, // corrected to axis max
112
+ outerRadius: '105%'
113
+ }
114
+
115
+ });
116
+ var axisProto = Axis.prototype,
117
+ tickProto = Tick.prototype;
118
+
119
+ /**
120
+ * Augmented methods for the x axis in order to hide it completely, used for the X axis in gauges
121
+ */
122
+ var hiddenAxisMixin = {
123
+ getOffset: noop,
124
+ redraw: function () {
125
+ this.isDirty = false; // prevent setting Y axis dirty
126
+ },
127
+ render: function () {
128
+ this.isDirty = false; // prevent setting Y axis dirty
129
+ },
130
+ setScale: noop,
131
+ setCategories: noop,
132
+ setTitle: noop
133
+ };
134
+
135
+ /**
136
+ * Augmented methods for the value axis
137
+ */
138
+ /*jslint unparam: true*/
139
+ var radialAxisMixin = {
140
+ isRadial: true,
141
+
142
+ /**
143
+ * The default options extend defaultYAxisOptions
144
+ */
145
+ defaultRadialGaugeOptions: {
146
+ labels: {
147
+ align: 'center',
148
+ x: 0,
149
+ y: null // auto
150
+ },
151
+ minorGridLineWidth: 0,
152
+ minorTickInterval: 'auto',
153
+ minorTickLength: 10,
154
+ minorTickPosition: 'inside',
155
+ minorTickWidth: 1,
156
+ plotBands: [],
157
+ tickLength: 10,
158
+ tickPosition: 'inside',
159
+ tickWidth: 2,
160
+ title: {
161
+ rotation: 0
162
+ },
163
+ zIndex: 2 // behind dials, points in the series group
164
+ },
165
+
166
+ // Circular axis around the perimeter of a polar chart
167
+ defaultRadialXOptions: {
168
+ gridLineWidth: 1, // spokes
169
+ labels: {
170
+ align: null, // auto
171
+ distance: 15,
172
+ x: 0,
173
+ y: null // auto
174
+ },
175
+ maxPadding: 0,
176
+ minPadding: 0,
177
+ plotBands: [],
178
+ showLastLabel: false,
179
+ tickLength: 0
180
+ },
181
+
182
+ // Radial axis, like a spoke in a polar chart
183
+ defaultRadialYOptions: {
184
+ gridLineInterpolation: 'circle',
185
+ labels: {
186
+ align: 'right',
187
+ x: -3,
188
+ y: -2
189
+ },
190
+ plotBands: [],
191
+ showLastLabel: false,
192
+ title: {
193
+ x: 4,
194
+ text: null,
195
+ rotation: 90
196
+ }
197
+ },
198
+
199
+ /**
200
+ * Merge and set options
201
+ */
202
+ setOptions: function (userOptions) {
203
+
204
+ this.options = merge(
205
+ this.defaultOptions,
206
+ this.defaultRadialOptions,
207
+ userOptions
208
+ );
209
+
210
+ },
211
+
212
+ /**
213
+ * Wrap the getOffset method to return zero offset for title or labels in a radial
214
+ * axis
215
+ */
216
+ getOffset: function () {
217
+ // Call the Axis prototype method (the method we're in now is on the instance)
218
+ axisProto.getOffset.call(this);
219
+
220
+ // Title or label offsets are not counted
221
+ this.chart.axisOffset[this.side] = 0;
222
+
223
+ // Set the center array
224
+ this.center = this.pane.center = seriesTypes.pie.prototype.getCenter.call(this.pane);
225
+ },
226
+
227
+
228
+ /**
229
+ * Get the path for the axis line. This method is also referenced in the getPlotLinePath
230
+ * method.
231
+ */
232
+ getLinePath: function (lineWidth, radius) {
233
+ var center = this.center;
234
+ radius = pick(radius, center[2] / 2 - this.offset);
235
+
236
+ return this.chart.renderer.symbols.arc(
237
+ this.left + center[0],
238
+ this.top + center[1],
239
+ radius,
240
+ radius,
241
+ {
242
+ start: this.startAngleRad,
243
+ end: this.endAngleRad,
244
+ open: true,
245
+ innerR: 0
246
+ }
247
+ );
248
+ },
249
+
250
+ /**
251
+ * Override setAxisTranslation by setting the translation to the difference
252
+ * in rotation. This allows the translate method to return angle for
253
+ * any given value.
254
+ */
255
+ setAxisTranslation: function () {
256
+
257
+ // Call uber method
258
+ axisProto.setAxisTranslation.call(this);
259
+
260
+ // Set transA and minPixelPadding
261
+ if (this.center) { // it's not defined the first time
262
+ if (this.isCircular) {
263
+
264
+ this.transA = (this.endAngleRad - this.startAngleRad) /
265
+ ((this.max - this.min) || 1);
266
+
267
+
268
+ } else {
269
+ this.transA = (this.center[2] / 2) / ((this.max - this.min) || 1);
270
+ }
271
+
272
+ if (this.isXAxis) {
273
+ this.minPixelPadding = this.transA * this.minPointOffset +
274
+ (this.reversed ? (this.endAngleRad - this.startAngleRad) / 4 : 0); // ???
275
+ }
276
+ }
277
+ },
278
+
279
+ /**
280
+ * In case of auto connect, add one closestPointRange to the max value right before
281
+ * tickPositions are computed, so that ticks will extend passed the real max.
282
+ */
283
+ beforeSetTickPositions: function () {
284
+ if (this.autoConnect) {
285
+ this.max += (this.categories && 1) || this.pointRange || this.closestPointRange; // #1197
286
+ }
287
+ },
288
+
289
+ /**
290
+ * Override the setAxisSize method to use the arc's circumference as length. This
291
+ * allows tickPixelInterval to apply to pixel lengths along the perimeter
292
+ */
293
+ setAxisSize: function () {
294
+
295
+ axisProto.setAxisSize.call(this);
296
+
297
+ if (this.center) { // it's not defined the first time
298
+ this.len = this.width = this.height = this.isCircular ?
299
+ this.center[2] * (this.endAngleRad - this.startAngleRad) / 2 :
300
+ this.center[2] / 2;
301
+ }
302
+ },
303
+
304
+ /**
305
+ * Returns the x, y coordinate of a point given by a value and a pixel distance
306
+ * from center
307
+ */
308
+ getPosition: function (value, length) {
309
+ if (!this.isCircular) {
310
+ length = this.translate(value);
311
+ value = this.min;
312
+ }
313
+
314
+ return this.postTranslate(
315
+ this.translate(value),
316
+ pick(length, this.center[2] / 2) - this.offset
317
+ );
318
+ },
319
+
320
+ /**
321
+ * Translate from intermediate plotX (angle), plotY (axis.len - radius) to final chart coordinates.
322
+ */
323
+ postTranslate: function (angle, radius) {
324
+
325
+ var chart = this.chart,
326
+ center = this.center;
327
+
328
+ angle = this.startAngleRad + angle;
329
+
330
+ return {
331
+ x: chart.plotLeft + center[0] + Math.cos(angle) * radius,
332
+ y: chart.plotTop + center[1] + Math.sin(angle) * radius
333
+ };
334
+
335
+ },
336
+
337
+ /**
338
+ * Find the path for plot bands along the radial axis
339
+ */
340
+ getPlotBandPath: function (from, to, options) {
341
+ var center = this.center,
342
+ startAngleRad = this.startAngleRad,
343
+ fullRadius = center[2] / 2,
344
+ radii = [
345
+ pick(options.outerRadius, '100%'),
346
+ options.innerRadius,
347
+ pick(options.thickness, 10)
348
+ ],
349
+ percentRegex = /%$/,
350
+ start,
351
+ end,
352
+ open,
353
+ isCircular = this.isCircular, // X axis in a polar chart
354
+ ret;
355
+
356
+ // Polygonal plot bands
357
+ if (this.options.gridLineInterpolation === 'polygon') {
358
+ ret = this.getPlotLinePath(from).concat(this.getPlotLinePath(to, true));
359
+
360
+ // Circular grid bands
361
+ } else {
362
+
363
+ // Plot bands on Y axis (radial axis) - inner and outer radius depend on to and from
364
+ if (!isCircular) {
365
+ radii[0] = this.translate(from);
366
+ radii[1] = this.translate(to);
367
+ }
368
+
369
+ // Convert percentages to pixel values
370
+ radii = map(radii, function (radius) {
371
+ if (percentRegex.test(radius)) {
372
+ radius = (pInt(radius, 10) * fullRadius) / 100;
373
+ }
374
+ return radius;
375
+ });
376
+
377
+ // Handle full circle
378
+ if (options.shape === 'circle' || !isCircular) {
379
+ start = -Math.PI / 2;
380
+ end = Math.PI * 1.5;
381
+ open = true;
382
+ } else {
383
+ start = startAngleRad + this.translate(from);
384
+ end = startAngleRad + this.translate(to);
385
+ }
386
+
387
+
388
+ ret = this.chart.renderer.symbols.arc(
389
+ this.left + center[0],
390
+ this.top + center[1],
391
+ radii[0],
392
+ radii[0],
393
+ {
394
+ start: start,
395
+ end: end,
396
+ innerR: pick(radii[1], radii[0] - radii[2]),
397
+ open: open
398
+ }
399
+ );
400
+ }
401
+
402
+ return ret;
403
+ },
404
+
405
+ /**
406
+ * Find the path for plot lines perpendicular to the radial axis.
407
+ */
408
+ getPlotLinePath: function (value, reverse) {
409
+ var axis = this,
410
+ center = axis.center,
411
+ chart = axis.chart,
412
+ end = axis.getPosition(value),
413
+ xAxis,
414
+ xy,
415
+ tickPositions,
416
+ ret;
417
+
418
+ // Spokes
419
+ if (axis.isCircular) {
420
+ ret = ['M', center[0] + chart.plotLeft, center[1] + chart.plotTop, 'L', end.x, end.y];
421
+
422
+ // Concentric circles
423
+ } else if (axis.options.gridLineInterpolation === 'circle') {
424
+ value = axis.translate(value);
425
+ if (value) { // a value of 0 is in the center
426
+ ret = axis.getLinePath(0, value);
427
+ }
428
+ // Concentric polygons
429
+ } else {
430
+ xAxis = chart.xAxis[0];
431
+ ret = [];
432
+ value = axis.translate(value);
433
+ tickPositions = xAxis.tickPositions;
434
+ if (xAxis.autoConnect) {
435
+ tickPositions = tickPositions.concat([tickPositions[0]]);
436
+ }
437
+ // Reverse the positions for concatenation of polygonal plot bands
438
+ if (reverse) {
439
+ tickPositions = [].concat(tickPositions).reverse();
440
+ }
441
+
442
+ each(tickPositions, function (pos, i) {
443
+ xy = xAxis.getPosition(pos, value);
444
+ ret.push(i ? 'L' : 'M', xy.x, xy.y);
445
+ });
446
+
447
+ }
448
+ return ret;
449
+ },
450
+
451
+ /**
452
+ * Find the position for the axis title, by default inside the gauge
453
+ */
454
+ getTitlePosition: function () {
455
+ var center = this.center,
456
+ chart = this.chart,
457
+ titleOptions = this.options.title;
458
+
459
+ return {
460
+ x: chart.plotLeft + center[0] + (titleOptions.x || 0),
461
+ y: chart.plotTop + center[1] - ({ high: 0.5, middle: 0.25, low: 0 }[titleOptions.align] *
462
+ center[2]) + (titleOptions.y || 0)
463
+ };
464
+ }
465
+
466
+ };
467
+ /*jslint unparam: false*/
468
+
469
+ /**
470
+ * Override axisProto.init to mix in special axis instance functions and function overrides
471
+ */
472
+ wrap(axisProto, 'init', function (proceed, chart, userOptions) {
473
+ var axis = this,
474
+ angular = chart.angular,
475
+ polar = chart.polar,
476
+ isX = userOptions.isX,
477
+ isHidden = angular && isX,
478
+ isCircular,
479
+ startAngleRad,
480
+ endAngleRad,
481
+ options,
482
+ chartOptions = chart.options,
483
+ paneIndex = userOptions.pane || 0,
484
+ pane,
485
+ paneOptions;
486
+
487
+ // Before prototype.init
488
+ if (angular) {
489
+ extend(this, isHidden ? hiddenAxisMixin : radialAxisMixin);
490
+ isCircular = !isX;
491
+ if (isCircular) {
492
+ this.defaultRadialOptions = this.defaultRadialGaugeOptions;
493
+ }
494
+
495
+ } else if (polar) {
496
+ //extend(this, userOptions.isX ? radialAxisMixin : radialAxisMixin);
497
+ extend(this, radialAxisMixin);
498
+ isCircular = isX;
499
+ this.defaultRadialOptions = isX ? this.defaultRadialXOptions : merge(this.defaultYAxisOptions, this.defaultRadialYOptions);
500
+
501
+ }
502
+
503
+ // Run prototype.init
504
+ proceed.call(this, chart, userOptions);
505
+
506
+ if (!isHidden && (angular || polar)) {
507
+ options = this.options;
508
+
509
+ // Create the pane and set the pane options.
510
+ if (!chart.panes) {
511
+ chart.panes = [];
512
+ }
513
+ this.pane = pane = chart.panes[paneIndex] = chart.panes[paneIndex] || new Pane(
514
+ splat(chartOptions.pane)[paneIndex],
515
+ chart,
516
+ axis
517
+ );
518
+ paneOptions = pane.options;
519
+
520
+
521
+ // Disable certain features on angular and polar axes
522
+ chart.inverted = false;
523
+ chartOptions.chart.zoomType = null;
524
+
525
+ // Start and end angle options are
526
+ // given in degrees relative to top, while internal computations are
527
+ // in radians relative to right (like SVG).
528
+ this.startAngleRad = startAngleRad = (paneOptions.startAngle - 90) * Math.PI / 180;
529
+ this.endAngleRad = endAngleRad = (pick(paneOptions.endAngle, paneOptions.startAngle + 360) - 90) * Math.PI / 180;
530
+ this.offset = options.offset || 0;
531
+
532
+ this.isCircular = isCircular;
533
+
534
+ // Automatically connect grid lines?
535
+ if (isCircular && userOptions.max === UNDEFINED && endAngleRad - startAngleRad === 2 * Math.PI) {
536
+ this.autoConnect = true;
537
+ }
538
+ }
539
+
540
+ });
541
+
542
+ /**
543
+ * Add special cases within the Tick class' methods for radial axes.
544
+ */
545
+ wrap(tickProto, 'getPosition', function (proceed, horiz, pos, tickmarkOffset, old) {
546
+ var axis = this.axis;
547
+
548
+ return axis.getPosition ?
549
+ axis.getPosition(pos) :
550
+ proceed.call(this, horiz, pos, tickmarkOffset, old);
551
+ });
552
+
553
+ /**
554
+ * Wrap the getLabelPosition function to find the center position of the label
555
+ * based on the distance option
556
+ */
557
+ wrap(tickProto, 'getLabelPosition', function (proceed, x, y, label, horiz, labelOptions, tickmarkOffset, index, step) {
558
+ var axis = this.axis,
559
+ optionsY = labelOptions.y,
560
+ ret,
561
+ align = labelOptions.align,
562
+ angle = (axis.translate(this.pos) + axis.startAngleRad + Math.PI / 2) / Math.PI * 180;
563
+
564
+ if (axis.isRadial) {
565
+ ret = axis.getPosition(this.pos, (axis.center[2] / 2) + pick(labelOptions.distance, -25));
566
+
567
+ // Automatically rotated
568
+ if (labelOptions.rotation === 'auto') {
569
+ label.attr({
570
+ rotation: angle
571
+ });
572
+
573
+ // Vertically centered
574
+ } else if (optionsY === null) {
575
+ optionsY = pInt(label.styles.lineHeight) * 0.9 - label.getBBox().height / 2;
576
+
577
+ }
578
+
579
+ // Automatic alignment
580
+ if (align === null) {
581
+ if (axis.isCircular) {
582
+ if (angle > 20 && angle < 160) {
583
+ align = 'left'; // right hemisphere
584
+ } else if (angle > 200 && angle < 340) {
585
+ align = 'right'; // left hemisphere
586
+ } else {
587
+ align = 'center'; // top or bottom
588
+ }
589
+ } else {
590
+ align = 'center';
591
+ }
592
+ label.attr({
593
+ align: align
594
+ });
595
+ }
596
+
597
+ ret.x += labelOptions.x;
598
+ ret.y += optionsY;
599
+
600
+ } else {
601
+ ret = proceed.call(this, x, y, label, horiz, labelOptions, tickmarkOffset, index, step);
602
+ }
603
+ return ret;
604
+ });
605
+
606
+ /**
607
+ * Wrap the getMarkPath function to return the path of the radial marker
608
+ */
609
+ wrap(tickProto, 'getMarkPath', function (proceed, x, y, tickLength, tickWidth, horiz, renderer) {
610
+ var axis = this.axis,
611
+ endPoint,
612
+ ret;
613
+
614
+ if (axis.isRadial) {
615
+ endPoint = axis.getPosition(this.pos, axis.center[2] / 2 + tickLength);
616
+ ret = [
617
+ 'M',
618
+ x,
619
+ y,
620
+ 'L',
621
+ endPoint.x,
622
+ endPoint.y
623
+ ];
624
+ } else {
625
+ ret = proceed.call(this, x, y, tickLength, tickWidth, horiz, renderer);
626
+ }
627
+ return ret;
628
+ });/*
629
+ * The AreaRangeSeries class
630
+ *
631
+ */
632
+
633
+ /**
634
+ * Extend the default options with map options
635
+ */
636
+ defaultPlotOptions.arearange = merge(defaultPlotOptions.area, {
637
+ lineWidth: 1,
638
+ marker: null,
639
+ threshold: null,
640
+ tooltip: {
641
+ pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.low}</b> - <b>{point.high}</b><br/>'
642
+ },
643
+ trackByArea: true,
644
+ dataLabels: {
645
+ verticalAlign: null,
646
+ xLow: 0,
647
+ xHigh: 0,
648
+ yLow: 0,
649
+ yHigh: 0
650
+ }
651
+ });
652
+
653
+ /**
654
+ * Add the series type
655
+ */
656
+ seriesTypes.arearange = Highcharts.extendClass(seriesTypes.area, {
657
+ type: 'arearange',
658
+ pointArrayMap: ['low', 'high'],
659
+ toYData: function (point) {
660
+ return [point.low, point.high];
661
+ },
662
+ pointValKey: 'low',
663
+
664
+ /**
665
+ * Extend getSegments to force null points if the higher value is null. #1703.
666
+ */
667
+ getSegments: function () {
668
+ var series = this;
669
+
670
+ each(series.points, function (point) {
671
+ if (!series.options.connectNulls && (point.low === null || point.high === null)) {
672
+ point.y = null;
673
+ } else if (point.low === null && point.high !== null) {
674
+ point.y = point.high;
675
+ }
676
+ });
677
+ Series.prototype.getSegments.call(this);
678
+ },
679
+
680
+ /**
681
+ * Translate data points from raw values x and y to plotX and plotY
682
+ */
683
+ translate: function () {
684
+ var series = this,
685
+ yAxis = series.yAxis;
686
+
687
+ seriesTypes.area.prototype.translate.apply(series);
688
+
689
+ // Set plotLow and plotHigh
690
+ each(series.points, function (point) {
691
+
692
+ var low = point.low,
693
+ high = point.high,
694
+ plotY = point.plotY;
695
+
696
+ if (high === null && low === null) {
697
+ point.y = null;
698
+ } else if (low === null) {
699
+ point.plotLow = point.plotY = null;
700
+ point.plotHigh = yAxis.toPixels(high, true);
701
+ } else if (high === null) {
702
+ point.plotLow = plotY;
703
+ point.plotHigh = null;
704
+ } else {
705
+ point.plotLow = plotY;
706
+ point.plotHigh = yAxis.toPixels(high, true);
707
+ }
708
+ });
709
+ },
710
+
711
+ /**
712
+ * Extend the line series' getSegmentPath method by applying the segment
713
+ * path to both lower and higher values of the range
714
+ */
715
+ getSegmentPath: function (segment) {
716
+
717
+ var lowSegment,
718
+ highSegment = [],
719
+ i = segment.length,
720
+ baseGetSegmentPath = Series.prototype.getSegmentPath,
721
+ point,
722
+ linePath,
723
+ lowerPath,
724
+ options = this.options,
725
+ step = options.step,
726
+ higherPath;
727
+
728
+ // Remove nulls from low segment
729
+ lowSegment = HighchartsAdapter.grep(segment, function (point) {
730
+ return point.plotLow !== null;
731
+ });
732
+
733
+ // Make a segment with plotX and plotY for the top values
734
+ while (i--) {
735
+ point = segment[i];
736
+ if (point.plotHigh !== null) {
737
+ highSegment.push({
738
+ plotX: point.plotX,
739
+ plotY: point.plotHigh
740
+ });
741
+ }
742
+ }
743
+
744
+ // Get the paths
745
+ lowerPath = baseGetSegmentPath.call(this, lowSegment);
746
+ if (step) {
747
+ if (step === true) {
748
+ step = 'left';
749
+ }
750
+ options.step = { left: 'right', center: 'center', right: 'left' }[step]; // swap for reading in getSegmentPath
751
+ }
752
+ higherPath = baseGetSegmentPath.call(this, highSegment);
753
+ options.step = step;
754
+
755
+ // Create a line on both top and bottom of the range
756
+ linePath = [].concat(lowerPath, higherPath);
757
+
758
+ // For the area path, we need to change the 'move' statement into 'lineTo' or 'curveTo'
759
+ higherPath[0] = 'L'; // this probably doesn't work for spline
760
+ this.areaPath = this.areaPath.concat(lowerPath, higherPath);
761
+
762
+ return linePath;
763
+ },
764
+
765
+ /**
766
+ * Extend the basic drawDataLabels method by running it for both lower and higher
767
+ * values.
768
+ */
769
+ drawDataLabels: function () {
770
+
771
+ var data = this.data,
772
+ length = data.length,
773
+ i,
774
+ originalDataLabels = [],
775
+ seriesProto = Series.prototype,
776
+ dataLabelOptions = this.options.dataLabels,
777
+ point,
778
+ inverted = this.chart.inverted;
779
+
780
+ if (dataLabelOptions.enabled || this._hasPointLabels) {
781
+
782
+ // Step 1: set preliminary values for plotY and dataLabel and draw the upper labels
783
+ i = length;
784
+ while (i--) {
785
+ point = data[i];
786
+
787
+ // Set preliminary values
788
+ point.y = point.high;
789
+ point.plotY = point.plotHigh;
790
+
791
+ // Store original data labels and set preliminary label objects to be picked up
792
+ // in the uber method
793
+ originalDataLabels[i] = point.dataLabel;
794
+ point.dataLabel = point.dataLabelUpper;
795
+
796
+ // Set the default offset
797
+ point.below = false;
798
+ if (inverted) {
799
+ dataLabelOptions.align = 'left';
800
+ dataLabelOptions.x = dataLabelOptions.xHigh;
801
+ } else {
802
+ dataLabelOptions.y = dataLabelOptions.yHigh;
803
+ }
804
+ }
805
+ seriesProto.drawDataLabels.apply(this, arguments); // #1209
806
+
807
+ // Step 2: reorganize and handle data labels for the lower values
808
+ i = length;
809
+ while (i--) {
810
+ point = data[i];
811
+
812
+ // Move the generated labels from step 1, and reassign the original data labels
813
+ point.dataLabelUpper = point.dataLabel;
814
+ point.dataLabel = originalDataLabels[i];
815
+
816
+ // Reset values
817
+ point.y = point.low;
818
+ point.plotY = point.plotLow;
819
+
820
+ // Set the default offset
821
+ point.below = true;
822
+ if (inverted) {
823
+ dataLabelOptions.align = 'right';
824
+ dataLabelOptions.x = dataLabelOptions.xLow;
825
+ } else {
826
+ dataLabelOptions.y = dataLabelOptions.yLow;
827
+ }
828
+ }
829
+ seriesProto.drawDataLabels.apply(this, arguments);
830
+ }
831
+
832
+ },
833
+
834
+ alignDataLabel: seriesTypes.column.prototype.alignDataLabel,
835
+
836
+ getSymbol: seriesTypes.column.prototype.getSymbol,
837
+
838
+ drawPoints: noop
839
+ });/**
840
+ * The AreaSplineRangeSeries class
841
+ */
842
+
843
+ defaultPlotOptions.areasplinerange = merge(defaultPlotOptions.arearange);
844
+
845
+ /**
846
+ * AreaSplineRangeSeries object
847
+ */
848
+ seriesTypes.areasplinerange = extendClass(seriesTypes.arearange, {
849
+ type: 'areasplinerange',
850
+ getPointSpline: seriesTypes.spline.prototype.getPointSpline
851
+ });/**
852
+ * The ColumnRangeSeries class
853
+ */
854
+ defaultPlotOptions.columnrange = merge(defaultPlotOptions.column, defaultPlotOptions.arearange, {
855
+ lineWidth: 1,
856
+ pointRange: null
857
+ });
858
+
859
+ /**
860
+ * ColumnRangeSeries object
861
+ */
862
+ seriesTypes.columnrange = extendClass(seriesTypes.arearange, {
863
+ type: 'columnrange',
864
+ /**
865
+ * Translate data points from raw values x and y to plotX and plotY
866
+ */
867
+ translate: function () {
868
+ var series = this,
869
+ yAxis = series.yAxis,
870
+ plotHigh;
871
+
872
+ colProto.translate.apply(series);
873
+
874
+ // Set plotLow and plotHigh
875
+ each(series.points, function (point) {
876
+ var shapeArgs = point.shapeArgs;
877
+
878
+ point.plotHigh = plotHigh = yAxis.translate(point.high, 0, 1, 0, 1);
879
+ point.plotLow = point.plotY;
880
+
881
+ // adjust shape
882
+ shapeArgs.y = plotHigh;
883
+ shapeArgs.height = point.plotY - plotHigh;
884
+
885
+ });
886
+ },
887
+ trackerGroups: ['group', 'dataLabels'],
888
+ drawGraph: noop,
889
+ pointAttrToOptions: colProto.pointAttrToOptions,
890
+ drawPoints: colProto.drawPoints,
891
+ drawTracker: colProto.drawTracker,
892
+ animate: colProto.animate,
893
+ getColumnMetrics: colProto.getColumnMetrics
894
+ });/*
895
+ * The GaugeSeries class
896
+ */
897
+
898
+
899
+
900
+ /**
901
+ * Extend the default options
902
+ */
903
+ defaultPlotOptions.gauge = merge(defaultPlotOptions.line, {
904
+ dataLabels: {
905
+ enabled: true,
906
+ y: 15,
907
+ borderWidth: 1,
908
+ borderColor: 'silver',
909
+ borderRadius: 3,
910
+ style: {
911
+ fontWeight: 'bold'
912
+ },
913
+ verticalAlign: 'top',
914
+ zIndex: 2
915
+ },
916
+ dial: {
917
+ // radius: '80%',
918
+ // backgroundColor: 'black',
919
+ // borderColor: 'silver',
920
+ // borderWidth: 0,
921
+ // baseWidth: 3,
922
+ // topWidth: 1,
923
+ // baseLength: '70%' // of radius
924
+ // rearLength: '10%'
925
+ },
926
+ pivot: {
927
+ //radius: 5,
928
+ //borderWidth: 0
929
+ //borderColor: 'silver',
930
+ //backgroundColor: 'black'
931
+ },
932
+ tooltip: {
933
+ headerFormat: ''
934
+ },
935
+ showInLegend: false
936
+ });
937
+
938
+ /**
939
+ * Extend the point object
940
+ */
941
+ var GaugePoint = Highcharts.extendClass(Highcharts.Point, {
942
+ /**
943
+ * Don't do any hover colors or anything
944
+ */
945
+ setState: function (state) {
946
+ this.state = state;
947
+ }
948
+ });
949
+
950
+
951
+ /**
952
+ * Add the series type
953
+ */
954
+ var GaugeSeries = {
955
+ type: 'gauge',
956
+ pointClass: GaugePoint,
957
+
958
+ // chart.angular will be set to true when a gauge series is present, and this will
959
+ // be used on the axes
960
+ angular: true,
961
+ drawGraph: noop,
962
+ trackerGroups: ['group', 'dataLabels'],
963
+
964
+ /**
965
+ * Calculate paths etc
966
+ */
967
+ translate: function () {
968
+
969
+ var series = this,
970
+ yAxis = series.yAxis,
971
+ options = series.options,
972
+ center = yAxis.center;
973
+
974
+ series.generatePoints();
975
+
976
+ each(series.points, function (point) {
977
+
978
+ var dialOptions = merge(options.dial, point.dial),
979
+ radius = (pInt(pick(dialOptions.radius, 80)) * center[2]) / 200,
980
+ baseLength = (pInt(pick(dialOptions.baseLength, 70)) * radius) / 100,
981
+ rearLength = (pInt(pick(dialOptions.rearLength, 10)) * radius) / 100,
982
+ baseWidth = dialOptions.baseWidth || 3,
983
+ topWidth = dialOptions.topWidth || 1,
984
+ rotation = yAxis.startAngleRad + yAxis.translate(point.y, null, null, null, true);
985
+
986
+ // Handle the wrap option
987
+ if (options.wrap === false) {
988
+ rotation = Math.max(yAxis.startAngleRad, Math.min(yAxis.endAngleRad, rotation));
989
+ }
990
+ rotation = rotation * 180 / Math.PI;
991
+
992
+ point.shapeType = 'path';
993
+ point.shapeArgs = {
994
+ d: dialOptions.path || [
995
+ 'M',
996
+ -rearLength, -baseWidth / 2,
997
+ 'L',
998
+ baseLength, -baseWidth / 2,
999
+ radius, -topWidth / 2,
1000
+ radius, topWidth / 2,
1001
+ baseLength, baseWidth / 2,
1002
+ -rearLength, baseWidth / 2,
1003
+ 'z'
1004
+ ],
1005
+ translateX: center[0],
1006
+ translateY: center[1],
1007
+ rotation: rotation
1008
+ };
1009
+
1010
+ // Positions for data label
1011
+ point.plotX = center[0];
1012
+ point.plotY = center[1];
1013
+ });
1014
+ },
1015
+
1016
+ /**
1017
+ * Draw the points where each point is one needle
1018
+ */
1019
+ drawPoints: function () {
1020
+
1021
+ var series = this,
1022
+ center = series.yAxis.center,
1023
+ pivot = series.pivot,
1024
+ options = series.options,
1025
+ pivotOptions = options.pivot,
1026
+ renderer = series.chart.renderer;
1027
+
1028
+ each(series.points, function (point) {
1029
+
1030
+ var graphic = point.graphic,
1031
+ shapeArgs = point.shapeArgs,
1032
+ d = shapeArgs.d,
1033
+ dialOptions = merge(options.dial, point.dial); // #1233
1034
+
1035
+ if (graphic) {
1036
+ graphic.animate(shapeArgs);
1037
+ shapeArgs.d = d; // animate alters it
1038
+ } else {
1039
+ point.graphic = renderer[point.shapeType](shapeArgs)
1040
+ .attr({
1041
+ stroke: dialOptions.borderColor || 'none',
1042
+ 'stroke-width': dialOptions.borderWidth || 0,
1043
+ fill: dialOptions.backgroundColor || 'black',
1044
+ rotation: shapeArgs.rotation // required by VML when animation is false
1045
+ })
1046
+ .add(series.group);
1047
+ }
1048
+ });
1049
+
1050
+ // Add or move the pivot
1051
+ if (pivot) {
1052
+ pivot.animate({ // #1235
1053
+ translateX: center[0],
1054
+ translateY: center[1]
1055
+ });
1056
+ } else {
1057
+ series.pivot = renderer.circle(0, 0, pick(pivotOptions.radius, 5))
1058
+ .attr({
1059
+ 'stroke-width': pivotOptions.borderWidth || 0,
1060
+ stroke: pivotOptions.borderColor || 'silver',
1061
+ fill: pivotOptions.backgroundColor || 'black'
1062
+ })
1063
+ .translate(center[0], center[1])
1064
+ .add(series.group);
1065
+ }
1066
+ },
1067
+
1068
+ /**
1069
+ * Animate the arrow up from startAngle
1070
+ */
1071
+ animate: function (init) {
1072
+ var series = this;
1073
+
1074
+ if (!init) {
1075
+ each(series.points, function (point) {
1076
+ var graphic = point.graphic;
1077
+
1078
+ if (graphic) {
1079
+ // start value
1080
+ graphic.attr({
1081
+ rotation: series.yAxis.startAngleRad * 180 / Math.PI
1082
+ });
1083
+
1084
+ // animate
1085
+ graphic.animate({
1086
+ rotation: point.shapeArgs.rotation
1087
+ }, series.options.animation);
1088
+ }
1089
+ });
1090
+
1091
+ // delete this function to allow it only once
1092
+ series.animate = null;
1093
+ }
1094
+ },
1095
+
1096
+ render: function () {
1097
+ this.group = this.plotGroup(
1098
+ 'group',
1099
+ 'series',
1100
+ this.visible ? 'visible' : 'hidden',
1101
+ this.options.zIndex,
1102
+ this.chart.seriesGroup
1103
+ );
1104
+ seriesTypes.pie.prototype.render.call(this);
1105
+ this.group.clip(this.chart.clipRect);
1106
+ },
1107
+
1108
+ setData: seriesTypes.pie.prototype.setData,
1109
+ drawTracker: seriesTypes.column.prototype.drawTracker
1110
+ };
1111
+ seriesTypes.gauge = Highcharts.extendClass(seriesTypes.line, GaugeSeries);/* ****************************************************************************
1112
+ * Start Box plot series code *
1113
+ *****************************************************************************/
1114
+
1115
+ // Set default options
1116
+ defaultPlotOptions.boxplot = merge(defaultPlotOptions.column, {
1117
+ fillColor: '#FFFFFF',
1118
+ lineWidth: 1,
1119
+ //medianColor: null,
1120
+ medianWidth: 2,
1121
+ states: {
1122
+ hover: {
1123
+ brightness: -0.3
1124
+ }
1125
+ },
1126
+ //stemColor: null,
1127
+ //stemDashStyle: 'solid'
1128
+ //stemWidth: null,
1129
+ threshold: null,
1130
+ tooltip: {
1131
+ pointFormat: '<span style="color:{series.color};font-weight:bold">{series.name}</span><br/>' +
1132
+ 'Minimum: {point.low}<br/>' +
1133
+ 'Lower quartile: {point.q1}<br/>' +
1134
+ 'Median: {point.median}<br/>' +
1135
+ 'Higher quartile: {point.q3}<br/>' +
1136
+ 'Maximum: {point.high}<br/>'
1137
+ },
1138
+ //whiskerColor: null,
1139
+ whiskerLength: '50%',
1140
+ whiskerWidth: 2
1141
+ });
1142
+
1143
+ // Create the series object
1144
+ seriesTypes.boxplot = extendClass(seriesTypes.column, {
1145
+ type: 'boxplot',
1146
+ pointArrayMap: ['low', 'q1', 'median', 'q3', 'high'], // array point configs are mapped to this
1147
+ toYData: function (point) { // return a plain array for speedy calculation
1148
+ return [point.low, point.q1, point.median, point.q3, point.high];
1149
+ },
1150
+ pointValKey: 'high', // defines the top of the tracker
1151
+
1152
+ /**
1153
+ * One-to-one mapping from options to SVG attributes
1154
+ */
1155
+ pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
1156
+ fill: 'fillColor',
1157
+ stroke: 'color',
1158
+ 'stroke-width': 'lineWidth'
1159
+ },
1160
+
1161
+ /**
1162
+ * Disable data labels for box plot
1163
+ */
1164
+ drawDataLabels: noop,
1165
+
1166
+ /**
1167
+ * Translate data points from raw values x and y to plotX and plotY
1168
+ */
1169
+ translate: function () {
1170
+ var series = this,
1171
+ yAxis = series.yAxis,
1172
+ pointArrayMap = series.pointArrayMap;
1173
+
1174
+ seriesTypes.column.prototype.translate.apply(series);
1175
+
1176
+ // do the translation on each point dimension
1177
+ each(series.points, function (point) {
1178
+ each(pointArrayMap, function (key) {
1179
+ if (point[key] !== null) {
1180
+ point[key + 'Plot'] = yAxis.translate(point[key], 0, 1, 0, 1);
1181
+ }
1182
+ });
1183
+ });
1184
+ },
1185
+
1186
+ /**
1187
+ * Draw the data points
1188
+ */
1189
+ drawPoints: function () {
1190
+ var series = this, //state = series.state,
1191
+ points = series.points,
1192
+ options = series.options,
1193
+ chart = series.chart,
1194
+ renderer = chart.renderer,
1195
+ pointAttr,
1196
+ q1Plot,
1197
+ q3Plot,
1198
+ highPlot,
1199
+ lowPlot,
1200
+ medianPlot,
1201
+ crispCorr,
1202
+ crispX,
1203
+ graphic,
1204
+ stemPath,
1205
+ stemAttr,
1206
+ boxPath,
1207
+ whiskersPath,
1208
+ whiskersAttr,
1209
+ medianPath,
1210
+ medianAttr,
1211
+ width,
1212
+ left,
1213
+ right,
1214
+ halfWidth,
1215
+ shapeArgs,
1216
+ color,
1217
+ doQuartiles = series.doQuartiles !== false, // error bar inherits this series type but doesn't do quartiles
1218
+ whiskerLength = parseInt(series.options.whiskerLength, 10) / 100;
1219
+
1220
+
1221
+ each(points, function (point) {
1222
+
1223
+ graphic = point.graphic;
1224
+ shapeArgs = point.shapeArgs; // the box
1225
+ stemAttr = {};
1226
+ whiskersAttr = {};
1227
+ medianAttr = {};
1228
+ color = point.color || series.color;
1229
+
1230
+ if (point.plotY !== UNDEFINED) {
1231
+
1232
+ pointAttr = point.pointAttr[point.selected ? 'selected' : ''];
1233
+
1234
+ // crisp vector coordinates
1235
+ width = shapeArgs.width;
1236
+ left = mathFloor(shapeArgs.x);
1237
+ right = left + width;
1238
+ halfWidth = mathRound(width / 2);
1239
+ //crispX = mathRound(left + halfWidth) + crispCorr;
1240
+ q1Plot = mathFloor(doQuartiles ? point.q1Plot : point.lowPlot);// + crispCorr;
1241
+ q3Plot = mathFloor(doQuartiles ? point.q3Plot : point.lowPlot);// + crispCorr;
1242
+ highPlot = mathFloor(point.highPlot);// + crispCorr;
1243
+ lowPlot = mathFloor(point.lowPlot);// + crispCorr;
1244
+
1245
+ // Stem attributes
1246
+ stemAttr.stroke = point.stemColor || options.stemColor || color;
1247
+ stemAttr['stroke-width'] = pick(point.stemWidth, options.stemWidth, options.lineWidth);
1248
+ stemAttr.dashstyle = point.stemDashStyle || options.stemDashStyle;
1249
+
1250
+ // Whiskers attributes
1251
+ whiskersAttr.stroke = point.whiskerColor || options.whiskerColor || color;
1252
+ whiskersAttr['stroke-width'] = pick(point.whiskerWidth, options.whiskerWidth, options.lineWidth);
1253
+
1254
+ // Median attributes
1255
+ medianAttr.stroke = point.medianColor || options.medianColor || color;
1256
+ medianAttr['stroke-width'] = pick(point.medianWidth, options.medianWidth, options.lineWidth);
1257
+
1258
+
1259
+ // The stem
1260
+ crispCorr = (stemAttr['stroke-width'] % 2) / 2;
1261
+ crispX = left + halfWidth + crispCorr;
1262
+ stemPath = [
1263
+ // stem up
1264
+ 'M',
1265
+ crispX, q3Plot,
1266
+ 'L',
1267
+ crispX, highPlot,
1268
+
1269
+ // stem down
1270
+ 'M',
1271
+ crispX, q1Plot,
1272
+ 'L',
1273
+ crispX, lowPlot,
1274
+ 'z'
1275
+ ];
1276
+
1277
+ // The box
1278
+ if (doQuartiles) {
1279
+ crispCorr = (pointAttr['stroke-width'] % 2) / 2;
1280
+ crispX = mathFloor(crispX) + crispCorr;
1281
+ q1Plot = mathFloor(q1Plot) + crispCorr;
1282
+ q3Plot = mathFloor(q3Plot) + crispCorr;
1283
+ left += crispCorr;
1284
+ right += crispCorr;
1285
+ boxPath = [
1286
+ 'M',
1287
+ left, q3Plot,
1288
+ 'L',
1289
+ left, q1Plot,
1290
+ 'L',
1291
+ right, q1Plot,
1292
+ 'L',
1293
+ right, q3Plot,
1294
+ 'L',
1295
+ left, q3Plot,
1296
+ 'z'
1297
+ ];
1298
+ }
1299
+
1300
+ // The whiskers
1301
+ if (whiskerLength) {
1302
+ crispCorr = (whiskersAttr['stroke-width'] % 2) / 2;
1303
+ highPlot = highPlot + crispCorr;
1304
+ lowPlot = lowPlot + crispCorr;
1305
+ whiskersPath = [
1306
+ // High whisker
1307
+ 'M',
1308
+ crispX - halfWidth * whiskerLength,
1309
+ highPlot,
1310
+ 'L',
1311
+ crispX + halfWidth * whiskerLength,
1312
+ highPlot,
1313
+
1314
+ // Low whisker
1315
+ 'M',
1316
+ crispX - halfWidth * whiskerLength,
1317
+ lowPlot,
1318
+ 'L',
1319
+ crispX + halfWidth * whiskerLength,
1320
+ lowPlot
1321
+ ];
1322
+ }
1323
+
1324
+ // The median
1325
+ crispCorr = (medianAttr['stroke-width'] % 2) / 2;
1326
+ medianPlot = mathRound(point.medianPlot) + crispCorr;
1327
+ medianPath = [
1328
+ 'M',
1329
+ left,
1330
+ medianPlot,
1331
+ 'L',
1332
+ right,
1333
+ medianPlot,
1334
+ 'z'
1335
+ ];
1336
+
1337
+ // Create or update the graphics
1338
+ if (graphic) { // update
1339
+
1340
+ point.stem.animate({ d: stemPath });
1341
+ if (whiskerLength) {
1342
+ point.whiskers.animate({ d: whiskersPath });
1343
+ }
1344
+ if (doQuartiles) {
1345
+ point.box.animate({ d: boxPath });
1346
+ }
1347
+ point.medianShape.animate({ d: medianPath });
1348
+
1349
+ } else { // create new
1350
+ point.graphic = graphic = renderer.g()
1351
+ .add(series.group);
1352
+
1353
+ point.stem = renderer.path(stemPath)
1354
+ .attr(stemAttr)
1355
+ .add(graphic);
1356
+
1357
+ if (whiskerLength) {
1358
+ point.whiskers = renderer.path(whiskersPath)
1359
+ .attr(whiskersAttr)
1360
+ .add(graphic);
1361
+ }
1362
+ if (doQuartiles) {
1363
+ point.box = renderer.path(boxPath)
1364
+ .attr(pointAttr)
1365
+ .add(graphic);
1366
+ }
1367
+ point.medianShape = renderer.path(medianPath)
1368
+ .attr(medianAttr)
1369
+ .add(graphic);
1370
+ }
1371
+ }
1372
+ });
1373
+
1374
+ }
1375
+
1376
+
1377
+ });
1378
+
1379
+ /* ****************************************************************************
1380
+ * End Box plot series code *
1381
+ *****************************************************************************/
1382
+ /* ****************************************************************************
1383
+ * Start error bar series code *
1384
+ *****************************************************************************/
1385
+
1386
+ // 1 - set default options
1387
+ defaultPlotOptions.errorbar = merge(defaultPlotOptions.boxplot, {
1388
+ color: '#000000',
1389
+ grouping: false,
1390
+ linkedTo: ':previous',
1391
+ tooltip: {
1392
+ pointFormat: defaultPlotOptions.arearange.tooltip.pointFormat
1393
+ },
1394
+ whiskerWidth: null
1395
+ });
1396
+
1397
+ // 2 - Create the series object
1398
+ seriesTypes.errorbar = extendClass(seriesTypes.boxplot, {
1399
+ type: 'errorbar',
1400
+ pointArrayMap: ['low', 'high'], // array point configs are mapped to this
1401
+ toYData: function (point) { // return a plain array for speedy calculation
1402
+ return [point.low, point.high];
1403
+ },
1404
+ pointValKey: 'high', // defines the top of the tracker
1405
+ doQuartiles: false,
1406
+
1407
+ /**
1408
+ * Get the width and X offset, either on top of the linked series column
1409
+ * or standalone
1410
+ */
1411
+ getColumnMetrics: function () {
1412
+ return (this.linkedParent && this.linkedParent.columnMetrics) ||
1413
+ seriesTypes.column.prototype.getColumnMetrics.call(this);
1414
+ }
1415
+ });
1416
+
1417
+ /* ****************************************************************************
1418
+ * End error bar series code *
1419
+ *****************************************************************************/
1420
+ /* ****************************************************************************
1421
+ * Start Waterfall series code *
1422
+ *****************************************************************************/
1423
+
1424
+ wrap(axisProto, 'getSeriesExtremes', function (proceed, renew) {
1425
+ // Run uber method
1426
+ proceed.call(this, renew);
1427
+
1428
+ if (this.isXAxis) {
1429
+ return;
1430
+ }
1431
+
1432
+ var axis = this,
1433
+ visitedStacks = [],
1434
+ resetMinMax = true;
1435
+
1436
+
1437
+ // recalculate extremes for each waterfall stack
1438
+ each(axis.series, function (series) {
1439
+ // process only visible, waterfall series, one from each stack
1440
+ if (!series.visible || !series.stackKey || series.type !== 'waterfall' || HighchartsAdapter.inArray(series.stackKey) !== -1) {
1441
+ return;
1442
+ }
1443
+
1444
+ // reset previously found dataMin and dataMax, do it only once
1445
+ if (resetMinMax) {
1446
+ axis.dataMin = axis.dataMax = null;
1447
+ resetMinMax = false;
1448
+ }
1449
+
1450
+
1451
+ var yData = series.processedYData,
1452
+ yDataLength = yData.length,
1453
+ seriesDataMin = yData[0],
1454
+ seriesDataMax = yData[0],
1455
+ threshold = series.options.threshold,
1456
+ stacks = axis.stacks,
1457
+ stackKey = series.stackKey,
1458
+ negKey = '-' + stackKey,
1459
+ total,
1460
+ previous,
1461
+ key,
1462
+ i;
1463
+
1464
+
1465
+ // set new stack totals including preceding values, finds new min and max values
1466
+ for (i = 0; i < yDataLength; i++) {
1467
+ key = yData[i] < threshold ? negKey : stackKey;
1468
+ total = stacks[key][i].total;
1469
+
1470
+ if (i > threshold) {
1471
+ total += previous;
1472
+ stacks[key][i].setTotal(total);
1473
+
1474
+ // _cum is used to avoid conflict with Series.translate method
1475
+ stacks[key][i]._cum = null;
1476
+ }
1477
+
1478
+
1479
+ // find min / max values
1480
+ if (total < seriesDataMin) {
1481
+ seriesDataMin = total;
1482
+ }
1483
+
1484
+ if (total > seriesDataMax) {
1485
+ seriesDataMax = total;
1486
+ }
1487
+
1488
+ previous = total;
1489
+ }
1490
+
1491
+
1492
+ // set new extremes
1493
+ series.dataMin = seriesDataMin;
1494
+ series.dataMax = seriesDataMax;
1495
+ axis.dataMin = mathMin(pick(axis.dataMin, seriesDataMin), seriesDataMin, threshold);
1496
+ axis.dataMax = mathMax(pick(axis.dataMax, seriesDataMax), seriesDataMax, threshold);
1497
+
1498
+ // remember series' stack key
1499
+ visitedStacks.push(series.stackKey);
1500
+
1501
+
1502
+
1503
+ // Adjust to threshold. This code is duplicated from the parent getSeriesExtremes method.
1504
+ if (typeof threshold === 'number') {
1505
+ if (axis.dataMin >= threshold) {
1506
+ axis.dataMin = threshold;
1507
+ axis.ignoreMinPadding = true;
1508
+ } else if (axis.dataMax < threshold) {
1509
+ axis.dataMax = threshold;
1510
+ axis.ignoreMaxPadding = true;
1511
+ }
1512
+ }
1513
+ });
1514
+ });
1515
+
1516
+
1517
+ // 1 - set default options
1518
+ defaultPlotOptions.waterfall = merge(defaultPlotOptions.column, {
1519
+ lineWidth: 1,
1520
+ lineColor: '#333',
1521
+ dashStyle: 'dot',
1522
+ borderColor: '#333'
1523
+ });
1524
+
1525
+
1526
+ // 2 - Create the series object
1527
+ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1528
+ type: 'waterfall',
1529
+
1530
+ upColorProp: 'fill',
1531
+
1532
+ pointArrayMap: ['y', 'low'],
1533
+
1534
+ pointValKey: 'y',
1535
+
1536
+ /**
1537
+ * Init waterfall series, force stacking
1538
+ */
1539
+ init: function (chart, options) {
1540
+ options.stacking = true;
1541
+ seriesTypes.column.prototype.init.call(this, chart, options);
1542
+ },
1543
+
1544
+
1545
+ /**
1546
+ * Translate data points from raw values
1547
+ */
1548
+ translate: function () {
1549
+ var series = this,
1550
+ options = series.options,
1551
+ axis = series.yAxis,
1552
+ len,
1553
+ i,
1554
+
1555
+ points,
1556
+ point,
1557
+ shapeArgs,
1558
+ sum,
1559
+ sumStart,
1560
+ subSum,
1561
+ subSumStart,
1562
+ edges,
1563
+ cumulative,
1564
+ prevStack,
1565
+ prevY,
1566
+ stack,
1567
+ crispCorr = (options.borderWidth % 2) / 2;
1568
+
1569
+ // run column series translate
1570
+ seriesTypes.column.prototype.translate.apply(this);
1571
+
1572
+
1573
+ points = this.points;
1574
+ subSumStart = sumStart = points[0];
1575
+ sum = subSum = points[0].y;
1576
+
1577
+ for (i = 1, len = points.length; i < len; i++) {
1578
+ // cache current point object
1579
+ point = points[i];
1580
+ shapeArgs = point.shapeArgs;
1581
+
1582
+ // get current and previous stack
1583
+ stack = series.getStack(i);
1584
+ prevStack = series.getStack(i - 1);
1585
+ prevY = series.getStackY(prevStack);
1586
+
1587
+ // set new intermediate sum values after reset
1588
+ if (subSumStart === null) {
1589
+ subSumStart = point;
1590
+ subSum = 0;
1591
+ }
1592
+
1593
+ // sum only points with value, not intermediate or total sum
1594
+ if (point.y && !point.isSum && !point.isIntermediateSum) {
1595
+ sum += point.y;
1596
+ subSum += point.y;
1597
+ }
1598
+
1599
+ // calculate sum points
1600
+ if (point.isSum || point.isIntermediateSum) {
1601
+
1602
+ if (point.isIntermediateSum) {
1603
+ edges = series.getSumEdges(subSumStart, points[i - 1]);
1604
+ point.y = subSum;
1605
+ subSumStart = null;
1606
+ } else {
1607
+ edges = series.getSumEdges(sumStart, points[i - 1]);
1608
+ point.y = sum;
1609
+ }
1610
+
1611
+ shapeArgs.y = point.plotY = edges[1];
1612
+ shapeArgs.height = edges[0] - edges[1];
1613
+
1614
+ // calculate other (up or down) points based on y value
1615
+ } else {
1616
+ // use "_cum" instead of already calculated "cum" to avoid reverse ordering negative columns
1617
+ cumulative = stack._cum === null ? prevStack.total : stack._cum;
1618
+ stack._cum = cumulative + point.y;
1619
+
1620
+ if (point.y < 0) {
1621
+ shapeArgs.y = mathCeil(axis.translate(cumulative, 0, 1)) - crispCorr;
1622
+ shapeArgs.height = mathCeil(axis.translate(stack._cum, 0, 1) - shapeArgs.y);
1623
+ } else {
1624
+ if (prevStack.total + point.y < 0) {
1625
+ shapeArgs.y = axis.translate(stack._cum, 0, 1);
1626
+ }
1627
+
1628
+ shapeArgs.height = mathFloor(prevY - shapeArgs.y);
1629
+ }
1630
+
1631
+ }
1632
+ }
1633
+ },
1634
+
1635
+ /**
1636
+ * Call default processData then override yData to reflect waterfall's extremes on yAxis
1637
+ */
1638
+ processData: function (force) {
1639
+ Series.prototype.processData.call(this, force);
1640
+
1641
+ var series = this,
1642
+ options = series.options,
1643
+ yData = series.yData,
1644
+ length = yData.length,
1645
+ prev,
1646
+ curr,
1647
+ subSum,
1648
+ sum,
1649
+ i;
1650
+
1651
+ prev = sum = subSum = options.threshold;
1652
+
1653
+ for (i = 0; i < length; i++) {
1654
+ curr = yData[i];
1655
+
1656
+ // processed yData only if it's not already processed
1657
+ if (curr !== null && typeof curr !== 'number') {
1658
+
1659
+ if (curr === "sum") {
1660
+ yData[i] = null;
1661
+
1662
+ } else if (curr === "intermediateSum") {
1663
+ yData[i] = null;
1664
+ subSum = prev;
1665
+
1666
+ } else {
1667
+ yData[i] = curr[0];// + prev;
1668
+ }
1669
+
1670
+ prev = yData[i];
1671
+ }
1672
+ }
1673
+ },
1674
+
1675
+ /**
1676
+ * Return [y, low] array, if low is not defined, it's replaced with null for further calculations
1677
+ */
1678
+ toYData: function (pt) {
1679
+ if (pt.isSum) {
1680
+ return "sum";
1681
+ } else if (pt.isIntermediateSum) {
1682
+ return "intermediateSum";
1683
+ }
1684
+
1685
+ return [pt.y];
1686
+ },
1687
+
1688
+ /**
1689
+ * Postprocess mapping between options and SVG attributes
1690
+ */
1691
+ getAttribs: function () {
1692
+ seriesTypes.column.prototype.getAttribs.apply(this, arguments);
1693
+
1694
+ var series = this,
1695
+ options = series.options,
1696
+ stateOptions = options.states,
1697
+ upColor = options.upColor || series.color,
1698
+ hoverColor = Highcharts.Color(upColor).brighten(0.1).get(),
1699
+ seriesDownPointAttr = merge(series.pointAttr),
1700
+ upColorProp = series.upColorProp;
1701
+
1702
+ seriesDownPointAttr[''][upColorProp] = upColor;
1703
+ seriesDownPointAttr.hover[upColorProp] = stateOptions.hover.upColor || hoverColor;
1704
+ seriesDownPointAttr.select[upColorProp] = stateOptions.select.upColor || upColor;
1705
+
1706
+ each(series.points, function (point) {
1707
+ if (point.y > 0 && !point.color) {
1708
+ point.pointAttr = seriesDownPointAttr;
1709
+ point.color = upColor;
1710
+ }
1711
+ });
1712
+ },
1713
+
1714
+ /**
1715
+ * Draw columns' connector lines
1716
+ */
1717
+ getGraphPath: function () {
1718
+
1719
+ var data = this.data,
1720
+ length = data.length,
1721
+ lineWidth = this.options.lineWidth + this.options.borderWidth,
1722
+ normalizer = mathRound(lineWidth) % 2 / 2,
1723
+ path = [],
1724
+ M = 'M',
1725
+ L = 'L',
1726
+ prevArgs,
1727
+ pointArgs,
1728
+ i,
1729
+ d;
1730
+
1731
+ for (i = 1; i < length; i++) {
1732
+ pointArgs = data[i].shapeArgs;
1733
+ prevArgs = data[i - 1].shapeArgs;
1734
+
1735
+ d = [
1736
+ M,
1737
+ prevArgs.x + prevArgs.width, prevArgs.y + normalizer,
1738
+ L,
1739
+ pointArgs.x, prevArgs.y + normalizer
1740
+ ];
1741
+
1742
+ if (data[i - 1].y < 0) {
1743
+ d[2] += prevArgs.height;
1744
+ d[5] += prevArgs.height;
1745
+ }
1746
+
1747
+ path = path.concat(d);
1748
+ }
1749
+
1750
+ return path;
1751
+ },
1752
+
1753
+ getStack: function (i) {
1754
+ var axis = this.yAxis,
1755
+ stacks = axis.stacks,
1756
+ key = this.stackKey;
1757
+
1758
+ if (this.processedYData[i] < this.options.threshold) {
1759
+ key = '-' + key;
1760
+ }
1761
+
1762
+ return stacks[key][i];
1763
+ },
1764
+
1765
+ getStackY: function (stack) {
1766
+ return mathCeil(this.yAxis.translate(stack.total, null, true));
1767
+ },
1768
+
1769
+ /**
1770
+ * Return array of top and bottom position for sum column based on given edge points
1771
+ */
1772
+ getSumEdges: function (pointA, pointB) {
1773
+ var valueA,
1774
+ valueB,
1775
+ tmp,
1776
+ threshold = this.options.threshold;
1777
+
1778
+ valueA = pointA.y >= threshold ? pointA.shapeArgs.y + pointA.shapeArgs.height : pointA.shapeArgs.y;
1779
+ valueB = pointB.y >= threshold ? pointB.shapeArgs.y : pointB.shapeArgs.y + pointB.shapeArgs.height;
1780
+
1781
+ if (valueB > valueA) {
1782
+ tmp = valueA;
1783
+ valueA = valueB;
1784
+ valueB = tmp;
1785
+ }
1786
+
1787
+ return [valueA, valueB];
1788
+ },
1789
+
1790
+ drawGraph: Series.prototype.drawGraph
1791
+ });
1792
+
1793
+ /* ****************************************************************************
1794
+ * End Waterfall series code *
1795
+ *****************************************************************************/
1796
+ /* ****************************************************************************
1797
+ * Start Bubble series code *
1798
+ *****************************************************************************/
1799
+
1800
+ // 1 - set default options
1801
+ defaultPlotOptions.bubble = merge(defaultPlotOptions.scatter, {
1802
+ dataLabels: {
1803
+ inside: true,
1804
+ style: {
1805
+ color: 'white',
1806
+ textShadow: '0px 0px 3px black'
1807
+ },
1808
+ verticalAlign: 'middle'
1809
+ },
1810
+ // displayNegative: true,
1811
+ marker: {
1812
+ // fillOpacity: 0.5,
1813
+ lineColor: null, // inherit from series.color
1814
+ lineWidth: 1
1815
+ },
1816
+ minSize: 8,
1817
+ maxSize: '20%',
1818
+ // negativeColor: null,
1819
+ tooltip: {
1820
+ pointFormat: '({point.x}, {point.y}), Size: {point.z}'
1821
+ },
1822
+ zThreshold: 0
1823
+ });
1824
+
1825
+ // 2 - Create the series object
1826
+ seriesTypes.bubble = extendClass(seriesTypes.scatter, {
1827
+ type: 'bubble',
1828
+ pointArrayMap: ['y', 'z'],
1829
+ trackerGroups: ['group', 'dataLabelsGroup'],
1830
+
1831
+ /**
1832
+ * Mapping between SVG attributes and the corresponding options
1833
+ */
1834
+ pointAttrToOptions: {
1835
+ stroke: 'lineColor',
1836
+ 'stroke-width': 'lineWidth',
1837
+ fill: 'fillColor'
1838
+ },
1839
+
1840
+ /**
1841
+ * Apply the fillOpacity to all fill positions
1842
+ */
1843
+ applyOpacity: function (fill) {
1844
+ var markerOptions = this.options.marker,
1845
+ fillOpacity = pick(markerOptions.fillOpacity, 0.5);
1846
+
1847
+ // When called from Legend.colorizeItem, the fill isn't predefined
1848
+ fill = fill || markerOptions.fillColor || this.color;
1849
+
1850
+ if (fillOpacity !== 1) {
1851
+ fill = Highcharts.Color(fill).setOpacity(fillOpacity).get('rgba');
1852
+ }
1853
+ return fill;
1854
+ },
1855
+
1856
+ /**
1857
+ * Extend the convertAttribs method by applying opacity to the fill
1858
+ */
1859
+ convertAttribs: function () {
1860
+ var obj = Series.prototype.convertAttribs.apply(this, arguments);
1861
+
1862
+ obj.fill = this.applyOpacity(obj.fill);
1863
+
1864
+ return obj;
1865
+ },
1866
+
1867
+ /**
1868
+ * Get the radius for each point based on the minSize, maxSize and each point's Z value. This
1869
+ * must be done prior to Series.translate because the axis needs to add padding in
1870
+ * accordance with the point sizes.
1871
+ */
1872
+ getRadii: function (zMin, zMax, minSize, maxSize) {
1873
+ var len,
1874
+ i,
1875
+ pos,
1876
+ zData = this.zData,
1877
+ radii = [],
1878
+ zRange;
1879
+
1880
+ // Set the shape type and arguments to be picked up in drawPoints
1881
+ for (i = 0, len = zData.length; i < len; i++) {
1882
+ zRange = zMax - zMin;
1883
+ pos = zRange > 0 ? // relative size, a number between 0 and 1
1884
+ (zData[i] - zMin) / (zMax - zMin) :
1885
+ 0.5;
1886
+ radii.push(math.ceil(minSize + pos * (maxSize - minSize)) / 2);
1887
+ }
1888
+ this.radii = radii;
1889
+ },
1890
+
1891
+ /**
1892
+ * Perform animation on the bubbles
1893
+ */
1894
+ animate: function (init) {
1895
+ var animation = this.options.animation;
1896
+
1897
+ if (!init) { // run the animation
1898
+ each(this.points, function (point) {
1899
+ var graphic = point.graphic,
1900
+ shapeArgs = point.shapeArgs;
1901
+
1902
+ if (graphic && shapeArgs) {
1903
+ // start values
1904
+ graphic.attr('r', 1);
1905
+
1906
+ // animate
1907
+ graphic.animate({
1908
+ r: shapeArgs.r
1909
+ }, animation);
1910
+ }
1911
+ });
1912
+
1913
+ // delete this function to allow it only once
1914
+ this.animate = null;
1915
+ }
1916
+ },
1917
+
1918
+ /**
1919
+ * Extend the base translate method to handle bubble size
1920
+ */
1921
+ translate: function () {
1922
+
1923
+ var i,
1924
+ data = this.data,
1925
+ point,
1926
+ radius,
1927
+ radii = this.radii;
1928
+
1929
+ // Run the parent method
1930
+ seriesTypes.scatter.prototype.translate.call(this);
1931
+
1932
+ // Set the shape type and arguments to be picked up in drawPoints
1933
+ i = data.length;
1934
+
1935
+ while (i--) {
1936
+ point = data[i];
1937
+ radius = radii ? radii[i] : 0; // #1737
1938
+
1939
+ // Flag for negativeColor to be applied in Series.js
1940
+ point.negative = point.z < (this.options.zThreshold || 0);
1941
+
1942
+ if (radius >= this.minPxSize / 2) {
1943
+ // Shape arguments
1944
+ point.shapeType = 'circle';
1945
+ point.shapeArgs = {
1946
+ x: point.plotX,
1947
+ y: point.plotY,
1948
+ r: radius
1949
+ };
1950
+
1951
+ // Alignment box for the data label
1952
+ point.dlBox = {
1953
+ x: point.plotX - radius,
1954
+ y: point.plotY - radius,
1955
+ width: 2 * radius,
1956
+ height: 2 * radius
1957
+ };
1958
+ } else { // below zThreshold
1959
+ point.shapeArgs = point.plotY = point.dlBox = UNDEFINED; // #1691
1960
+ }
1961
+ }
1962
+ },
1963
+
1964
+ /**
1965
+ * Get the series' symbol in the legend
1966
+ *
1967
+ * @param {Object} legend The legend object
1968
+ * @param {Object} item The series (this) or point
1969
+ */
1970
+ drawLegendSymbol: function (legend, item) {
1971
+ var radius = pInt(legend.itemStyle.fontSize) / 2;
1972
+
1973
+ item.legendSymbol = this.chart.renderer.circle(
1974
+ radius,
1975
+ legend.baseline - radius,
1976
+ radius
1977
+ ).attr({
1978
+ zIndex: 3
1979
+ }).add(item.legendGroup);
1980
+
1981
+ },
1982
+
1983
+ drawPoints: seriesTypes.column.prototype.drawPoints,
1984
+ alignDataLabel: seriesTypes.column.prototype.alignDataLabel
1985
+ });
1986
+
1987
+ /**
1988
+ * Add logic to pad each axis with the amount of pixels
1989
+ * necessary to avoid the bubbles to overflow.
1990
+ */
1991
+ Axis.prototype.beforePadding = function () {
1992
+ var axis = this,
1993
+ axisLength = this.len,
1994
+ chart = this.chart,
1995
+ pxMin = 0,
1996
+ pxMax = axisLength,
1997
+ isXAxis = this.isXAxis,
1998
+ dataKey = isXAxis ? 'xData' : 'yData',
1999
+ min = this.min,
2000
+ extremes = {},
2001
+ smallestSize = math.min(chart.plotWidth, chart.plotHeight),
2002
+ zMin = Number.MAX_VALUE,
2003
+ zMax = -Number.MAX_VALUE,
2004
+ range = this.max - min,
2005
+ transA = axisLength / range,
2006
+ activeSeries = [];
2007
+
2008
+ // Handle padding on the second pass, or on redraw
2009
+ if (this.tickPositions) {
2010
+ each(this.series, function (series) {
2011
+
2012
+ var seriesOptions = series.options,
2013
+ zData;
2014
+
2015
+ if (series.type === 'bubble' && series.visible) {
2016
+
2017
+ // Correction for #1673
2018
+ axis.allowZoomOutside = true;
2019
+
2020
+ // Cache it
2021
+ activeSeries.push(series);
2022
+
2023
+ if (isXAxis) { // because X axis is evaluated first
2024
+
2025
+ // For each series, translate the size extremes to pixel values
2026
+ each(['minSize', 'maxSize'], function (prop) {
2027
+ var length = seriesOptions[prop],
2028
+ isPercent = /%$/.test(length);
2029
+
2030
+ length = pInt(length);
2031
+ extremes[prop] = isPercent ?
2032
+ smallestSize * length / 100 :
2033
+ length;
2034
+
2035
+ });
2036
+ series.minPxSize = extremes.minSize;
2037
+
2038
+ // Find the min and max Z
2039
+ zData = series.zData;
2040
+ if (zData.length) { // #1735
2041
+ zMin = math.min(
2042
+ zMin,
2043
+ math.max(
2044
+ arrayMin(zData),
2045
+ seriesOptions.displayNegative === false ? seriesOptions.zThreshold : -Number.MAX_VALUE
2046
+ )
2047
+ );
2048
+ zMax = math.max(zMax, arrayMax(zData));
2049
+ }
2050
+ }
2051
+ }
2052
+ });
2053
+
2054
+ each(activeSeries, function (series) {
2055
+
2056
+ var data = series[dataKey],
2057
+ i = data.length,
2058
+ radius;
2059
+
2060
+ if (isXAxis) {
2061
+ series.getRadii(zMin, zMax, extremes.minSize, extremes.maxSize);
2062
+ }
2063
+
2064
+ if (range > 0) {
2065
+ while (i--) {
2066
+ radius = series.radii[i];
2067
+ pxMin = Math.min(((data[i] - min) * transA) - radius, pxMin);
2068
+ pxMax = Math.max(((data[i] - min) * transA) + radius, pxMax);
2069
+ }
2070
+ }
2071
+ });
2072
+
2073
+ if (range > 0 && pick(this.options.min, this.userMin) === UNDEFINED && pick(this.options.max, this.userMax) === UNDEFINED) {
2074
+ pxMax -= axisLength;
2075
+ transA *= (axisLength + pxMin - pxMax) / axisLength;
2076
+ this.min += pxMin / transA;
2077
+ this.max += pxMax / transA;
2078
+ }
2079
+ }
2080
+ };
2081
+
2082
+ /* ****************************************************************************
2083
+ * End Bubble series code *
2084
+ *****************************************************************************/
2085
+ /**
2086
+ * Extensions for polar charts. Additionally, much of the geometry required for polar charts is
2087
+ * gathered in RadialAxes.js.
2088
+ *
2089
+ */
2090
+
2091
+ var seriesProto = Series.prototype,
2092
+ pointerProto = Highcharts.Pointer.prototype;
2093
+
2094
+
2095
+
2096
+ /**
2097
+ * Translate a point's plotX and plotY from the internal angle and radius measures to
2098
+ * true plotX, plotY coordinates
2099
+ */
2100
+ seriesProto.toXY = function (point) {
2101
+ var xy,
2102
+ chart = this.chart,
2103
+ plotX = point.plotX,
2104
+ plotY = point.plotY;
2105
+
2106
+ // Save rectangular plotX, plotY for later computation
2107
+ point.rectPlotX = plotX;
2108
+ point.rectPlotY = plotY;
2109
+
2110
+ // Record the angle in degrees for use in tooltip
2111
+ point.clientX = plotX / Math.PI * 180;
2112
+
2113
+ // Find the polar plotX and plotY
2114
+ xy = this.xAxis.postTranslate(point.plotX, this.yAxis.len - plotY);
2115
+ point.plotX = point.polarPlotX = xy.x - chart.plotLeft;
2116
+ point.plotY = point.polarPlotY = xy.y - chart.plotTop;
2117
+ };
2118
+
2119
+
2120
+ /**
2121
+ * Add some special init logic to areas and areasplines
2122
+ */
2123
+ function initArea(proceed, chart, options) {
2124
+ proceed.call(this, chart, options);
2125
+ if (this.chart.polar) {
2126
+
2127
+ /**
2128
+ * Overridden method to close a segment path. While in a cartesian plane the area
2129
+ * goes down to the threshold, in the polar chart it goes to the center.
2130
+ */
2131
+ this.closeSegment = function (path) {
2132
+ var center = this.xAxis.center;
2133
+ path.push(
2134
+ 'L',
2135
+ center[0],
2136
+ center[1]
2137
+ );
2138
+ };
2139
+
2140
+ // Instead of complicated logic to draw an area around the inner area in a stack,
2141
+ // just draw it behind
2142
+ this.closedStacks = true;
2143
+ }
2144
+ }
2145
+ wrap(seriesTypes.area.prototype, 'init', initArea);
2146
+ wrap(seriesTypes.areaspline.prototype, 'init', initArea);
2147
+
2148
+
2149
+ /**
2150
+ * Overridden method for calculating a spline from one point to the next
2151
+ */
2152
+ wrap(seriesTypes.spline.prototype, 'getPointSpline', function (proceed, segment, point, i) {
2153
+
2154
+ var ret,
2155
+ smoothing = 1.5, // 1 means control points midway between points, 2 means 1/3 from the point, 3 is 1/4 etc;
2156
+ denom = smoothing + 1,
2157
+ plotX,
2158
+ plotY,
2159
+ lastPoint,
2160
+ nextPoint,
2161
+ lastX,
2162
+ lastY,
2163
+ nextX,
2164
+ nextY,
2165
+ leftContX,
2166
+ leftContY,
2167
+ rightContX,
2168
+ rightContY,
2169
+ distanceLeftControlPoint,
2170
+ distanceRightControlPoint,
2171
+ leftContAngle,
2172
+ rightContAngle,
2173
+ jointAngle;
2174
+
2175
+
2176
+ if (this.chart.polar) {
2177
+
2178
+ plotX = point.plotX;
2179
+ plotY = point.plotY;
2180
+ lastPoint = segment[i - 1];
2181
+ nextPoint = segment[i + 1];
2182
+
2183
+ // Connect ends
2184
+ if (this.connectEnds) {
2185
+ if (!lastPoint) {
2186
+ lastPoint = segment[segment.length - 2]; // not the last but the second last, because the segment is already connected
2187
+ }
2188
+ if (!nextPoint) {
2189
+ nextPoint = segment[1];
2190
+ }
2191
+ }
2192
+
2193
+ // find control points
2194
+ if (lastPoint && nextPoint) {
2195
+
2196
+ lastX = lastPoint.plotX;
2197
+ lastY = lastPoint.plotY;
2198
+ nextX = nextPoint.plotX;
2199
+ nextY = nextPoint.plotY;
2200
+ leftContX = (smoothing * plotX + lastX) / denom;
2201
+ leftContY = (smoothing * plotY + lastY) / denom;
2202
+ rightContX = (smoothing * plotX + nextX) / denom;
2203
+ rightContY = (smoothing * plotY + nextY) / denom;
2204
+ distanceLeftControlPoint = Math.sqrt(Math.pow(leftContX - plotX, 2) + Math.pow(leftContY - plotY, 2));
2205
+ distanceRightControlPoint = Math.sqrt(Math.pow(rightContX - plotX, 2) + Math.pow(rightContY - plotY, 2));
2206
+ leftContAngle = Math.atan2(leftContY - plotY, leftContX - plotX);
2207
+ rightContAngle = Math.atan2(rightContY - plotY, rightContX - plotX);
2208
+ jointAngle = (Math.PI / 2) + ((leftContAngle + rightContAngle) / 2);
2209
+
2210
+
2211
+ // Ensure the right direction, jointAngle should be in the same quadrant as leftContAngle
2212
+ if (Math.abs(leftContAngle - jointAngle) > Math.PI / 2) {
2213
+ jointAngle -= Math.PI;
2214
+ }
2215
+
2216
+ // Find the corrected control points for a spline straight through the point
2217
+ leftContX = plotX + Math.cos(jointAngle) * distanceLeftControlPoint;
2218
+ leftContY = plotY + Math.sin(jointAngle) * distanceLeftControlPoint;
2219
+ rightContX = plotX + Math.cos(Math.PI + jointAngle) * distanceRightControlPoint;
2220
+ rightContY = plotY + Math.sin(Math.PI + jointAngle) * distanceRightControlPoint;
2221
+
2222
+ // Record for drawing in next point
2223
+ point.rightContX = rightContX;
2224
+ point.rightContY = rightContY;
2225
+
2226
+ }
2227
+
2228
+
2229
+ // moveTo or lineTo
2230
+ if (!i) {
2231
+ ret = ['M', plotX, plotY];
2232
+ } else { // curve from last point to this
2233
+ ret = [
2234
+ 'C',
2235
+ lastPoint.rightContX || lastPoint.plotX,
2236
+ lastPoint.rightContY || lastPoint.plotY,
2237
+ leftContX || plotX,
2238
+ leftContY || plotY,
2239
+ plotX,
2240
+ plotY
2241
+ ];
2242
+ lastPoint.rightContX = lastPoint.rightContY = null; // reset for updating series later
2243
+ }
2244
+
2245
+
2246
+ } else {
2247
+ ret = proceed.call(this, segment, point, i);
2248
+ }
2249
+ return ret;
2250
+ });
2251
+
2252
+ /**
2253
+ * Extend translate. The plotX and plotY values are computed as if the polar chart were a
2254
+ * cartesian plane, where plotX denotes the angle in radians and (yAxis.len - plotY) is the pixel distance from
2255
+ * center.
2256
+ */
2257
+ wrap(seriesProto, 'translate', function (proceed) {
2258
+
2259
+ // Run uber method
2260
+ proceed.call(this);
2261
+
2262
+ // Postprocess plot coordinates
2263
+ if (this.chart.polar && !this.preventPostTranslate) {
2264
+ var points = this.points,
2265
+ i = points.length;
2266
+ while (i--) {
2267
+ // Translate plotX, plotY from angle and radius to true plot coordinates
2268
+ this.toXY(points[i]);
2269
+ }
2270
+ }
2271
+ });
2272
+
2273
+ /**
2274
+ * Extend getSegmentPath to allow connecting ends across 0 to provide a closed circle in
2275
+ * line-like series.
2276
+ */
2277
+ wrap(seriesProto, 'getSegmentPath', function (proceed, segment) {
2278
+
2279
+ var points = this.points;
2280
+
2281
+ // Connect the path
2282
+ if (this.chart.polar && this.options.connectEnds !== false &&
2283
+ segment[segment.length - 1] === points[points.length - 1] && points[0].y !== null) {
2284
+ this.connectEnds = true; // re-used in splines
2285
+ segment = [].concat(segment, [points[0]]);
2286
+ }
2287
+
2288
+ // Run uber method
2289
+ return proceed.call(this, segment);
2290
+
2291
+ });
2292
+
2293
+
2294
+ function polarAnimate(proceed, init) {
2295
+ var chart = this.chart,
2296
+ animation = this.options.animation,
2297
+ group = this.group,
2298
+ markerGroup = this.markerGroup,
2299
+ center = this.xAxis.center,
2300
+ plotLeft = chart.plotLeft,
2301
+ plotTop = chart.plotTop,
2302
+ attribs;
2303
+
2304
+ // Specific animation for polar charts
2305
+ if (chart.polar) {
2306
+
2307
+ // Enable animation on polar charts only in SVG. In VML, the scaling is different, plus animation
2308
+ // would be so slow it would't matter.
2309
+ if (chart.renderer.isSVG) {
2310
+
2311
+ if (animation === true) {
2312
+ animation = {};
2313
+ }
2314
+
2315
+ // Initialize the animation
2316
+ if (init) {
2317
+
2318
+ // Scale down the group and place it in the center
2319
+ attribs = {
2320
+ translateX: center[0] + plotLeft,
2321
+ translateY: center[1] + plotTop,
2322
+ scaleX: 0.001, // #1499
2323
+ scaleY: 0.001
2324
+ };
2325
+
2326
+ group.attr(attribs);
2327
+ if (markerGroup) {
2328
+ markerGroup.attrSetters = group.attrSetters;
2329
+ markerGroup.attr(attribs);
2330
+ }
2331
+
2332
+ // Run the animation
2333
+ } else {
2334
+ attribs = {
2335
+ translateX: plotLeft,
2336
+ translateY: plotTop,
2337
+ scaleX: 1,
2338
+ scaleY: 1
2339
+ };
2340
+ group.animate(attribs, animation);
2341
+ if (markerGroup) {
2342
+ markerGroup.animate(attribs, animation);
2343
+ }
2344
+
2345
+ // Delete this function to allow it only once
2346
+ this.animate = null;
2347
+ }
2348
+ }
2349
+
2350
+ // For non-polar charts, revert to the basic animation
2351
+ } else {
2352
+ proceed.call(this, init);
2353
+ }
2354
+ }
2355
+
2356
+ // Define the animate method for both regular series and column series and their derivatives
2357
+ wrap(seriesProto, 'animate', polarAnimate);
2358
+ wrap(colProto, 'animate', polarAnimate);
2359
+
2360
+
2361
+ /**
2362
+ * Throw in a couple of properties to let setTooltipPoints know we're indexing the points
2363
+ * in degrees (0-360), not plot pixel width.
2364
+ */
2365
+ wrap(seriesProto, 'setTooltipPoints', function (proceed, renew) {
2366
+
2367
+ if (this.chart.polar) {
2368
+ extend(this.xAxis, {
2369
+ tooltipLen: 360 // degrees are the resolution unit of the tooltipPoints array
2370
+ });
2371
+ }
2372
+
2373
+ // Run uber method
2374
+ return proceed.call(this, renew);
2375
+ });
2376
+
2377
+
2378
+ /**
2379
+ * Extend the column prototype's translate method
2380
+ */
2381
+ wrap(colProto, 'translate', function (proceed) {
2382
+
2383
+ var xAxis = this.xAxis,
2384
+ len = this.yAxis.len,
2385
+ center = xAxis.center,
2386
+ startAngleRad = xAxis.startAngleRad,
2387
+ renderer = this.chart.renderer,
2388
+ start,
2389
+ points,
2390
+ point,
2391
+ i;
2392
+
2393
+ this.preventPostTranslate = true;
2394
+
2395
+ // Run uber method
2396
+ proceed.call(this);
2397
+
2398
+ // Postprocess plot coordinates
2399
+ if (xAxis.isRadial) {
2400
+ points = this.points;
2401
+ i = points.length;
2402
+ while (i--) {
2403
+ point = points[i];
2404
+ start = point.barX + startAngleRad;
2405
+ point.shapeType = 'path';
2406
+ point.shapeArgs = {
2407
+ d: renderer.symbols.arc(
2408
+ center[0],
2409
+ center[1],
2410
+ len - point.plotY,
2411
+ null,
2412
+ {
2413
+ start: start,
2414
+ end: start + point.pointWidth,
2415
+ innerR: len - pick(point.yBottom, len)
2416
+ }
2417
+ )
2418
+ };
2419
+ this.toXY(point); // provide correct plotX, plotY for tooltip
2420
+ }
2421
+ }
2422
+ });
2423
+
2424
+
2425
+ /**
2426
+ * Align column data labels outside the columns. #1199.
2427
+ */
2428
+ wrap(colProto, 'alignDataLabel', function (proceed, point, dataLabel, options, alignTo, isNew) {
2429
+
2430
+ if (this.chart.polar) {
2431
+ var angle = point.rectPlotX / Math.PI * 180,
2432
+ align,
2433
+ verticalAlign;
2434
+
2435
+ // Align nicely outside the perimeter of the columns
2436
+ if (options.align === null) {
2437
+ if (angle > 20 && angle < 160) {
2438
+ align = 'left'; // right hemisphere
2439
+ } else if (angle > 200 && angle < 340) {
2440
+ align = 'right'; // left hemisphere
2441
+ } else {
2442
+ align = 'center'; // top or bottom
2443
+ }
2444
+ options.align = align;
2445
+ }
2446
+ if (options.verticalAlign === null) {
2447
+ if (angle < 45 || angle > 315) {
2448
+ verticalAlign = 'bottom'; // top part
2449
+ } else if (angle > 135 && angle < 225) {
2450
+ verticalAlign = 'top'; // bottom part
2451
+ } else {
2452
+ verticalAlign = 'middle'; // left or right
2453
+ }
2454
+ options.verticalAlign = verticalAlign;
2455
+ }
2456
+
2457
+ seriesProto.alignDataLabel.call(this, point, dataLabel, options, alignTo, isNew);
2458
+ } else {
2459
+ proceed.call(this, point, dataLabel, options, alignTo, isNew);
2460
+ }
2461
+
2462
+ });
2463
+
2464
+ /**
2465
+ * Extend the mouse tracker to return the tooltip position index in terms of
2466
+ * degrees rather than pixels
2467
+ */
2468
+ wrap(pointerProto, 'getIndex', function (proceed, e) {
2469
+ var ret,
2470
+ chart = this.chart,
2471
+ center,
2472
+ x,
2473
+ y;
2474
+
2475
+ if (chart.polar) {
2476
+ center = chart.xAxis[0].center;
2477
+ x = e.chartX - center[0] - chart.plotLeft;
2478
+ y = e.chartY - center[1] - chart.plotTop;
2479
+
2480
+ ret = 180 - Math.round(Math.atan2(x, y) / Math.PI * 180);
2481
+
2482
+ } else {
2483
+
2484
+ // Run uber method
2485
+ ret = proceed.call(this, e);
2486
+ }
2487
+ return ret;
2488
+ });
2489
+
2490
+ /**
2491
+ * Extend getCoordinates to prepare for polar axis values
2492
+ */
2493
+ wrap(pointerProto, 'getCoordinates', function (proceed, e) {
2494
+ var chart = this.chart,
2495
+ ret = {
2496
+ xAxis: [],
2497
+ yAxis: []
2498
+ };
2499
+
2500
+ if (chart.polar) {
2501
+
2502
+ each(chart.axes, function (axis) {
2503
+ var isXAxis = axis.isXAxis,
2504
+ center = axis.center,
2505
+ x = e.chartX - center[0] - chart.plotLeft,
2506
+ y = e.chartY - center[1] - chart.plotTop;
2507
+
2508
+ ret[isXAxis ? 'xAxis' : 'yAxis'].push({
2509
+ axis: axis,
2510
+ value: axis.translate(
2511
+ isXAxis ?
2512
+ Math.PI - Math.atan2(x, y) : // angle
2513
+ Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)), // distance from center
2514
+ true
2515
+ )
2516
+ });
2517
+ });
2518
+
2519
+ } else {
2520
+ ret = proceed.call(this, e);
2521
+ }
2522
+
2523
+ return ret;
2524
+ });
2525
+ }(Highcharts));