highcharts-rails 3.0.1.5 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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));