highcharts-js-rails 0.1.10 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,8 @@
1
+ ## v0.1.11 (2012-12-13) ##
2
+
3
+ * Add support for series data point hashes. (Thanks tanelj!)
4
+ * Update Highcharts to 2.3.3.
5
+
1
6
  ## v0.1.10 (2012-09-06) ##
2
7
 
3
8
  * Update Highcharts to 2.3.2.
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'highcharts-js-rails'
6
- s.version = '0.1.10'
6
+ s.version = '0.1.11'
7
7
  s.authors = ['Alex Robbin']
8
8
  s.email = ['agrobbin@gmail.com']
9
9
  s.homepage = 'https://github.com/agrobbin/highcharts-js-rails'
@@ -2,7 +2,19 @@ class Highcharts
2
2
  class Series < Base
3
3
 
4
4
  def to_json
5
- @options[:data] = options[:data].first.is_a?(Array) ? options[:data].collect {|d| [d.first, d.last.to_f]} : options[:data].collect(&:to_f)
5
+ @options[:data] = if options[:data].first.is_a?(Array) || options[:data].first.is_a?(Hash)
6
+ options[:data].collect do |d|
7
+ if d.is_a?(Array)
8
+ [d.first, d.last.to_f]
9
+ else
10
+ d[:y] = d[:y].to_f
11
+ d
12
+ end
13
+ end
14
+ else
15
+ options[:data].collect(&:to_f)
16
+ end
17
+
6
18
  super
7
19
  end
8
20
 
@@ -1,34 +1,35 @@
1
1
  /*
2
- Highcharts JS v2.3.2 (2012-08-31)
2
+ Highcharts JS v2.3.3 (2012-10-04)
3
3
 
4
4
  (c) 2009-2011 Torstein Hønsi
5
5
 
6
6
  License: www.highcharts.com/license
7
7
  */
8
- (function(h,t){function z(a,b,c){this.init.call(this,a,b,c)}function A(a,b,c){a.call(this,b,c);if(this.chart.polar)this.closeSegment=function(a){var b=this.xAxis.center;a.push("L",b[0],b[1])},this.closedStacks=!0}function B(a,b){var c=this.chart,d=this.options.animation,f=this.group,e=this.markerGroup,g=this.xAxis.center,i=c.plotLeft,m=c.plotTop;if(c.polar){if(c.renderer.isSVG)if(d===!0&&(d={}),b){if(f.attrSetters.scaleX=f.attrSetters.scaleY=function(a,b){this[b]=a;this.scaleX!==t&&this.scaleY!==
9
- t&&this.element.setAttribute("transform","translate("+this.translateX+","+this.translateY+") scale("+this.scaleX+","+this.scaleY+")");return!1},c={translateX:g[0]+i,translateY:g[1]+m,scaleX:0,scaleY:0},f.attr(c),e)e.attrSetters=f.attrSetters,e.attr(c)}else c={translateX:i,translateY:m,scaleX:1,scaleY:1},f.animate(c,d),e&&e.animate(c,d),this.animate=null}else a.call(this,b)}var p=h.each,u=h.extend,o=h.merge,D=h.map,n=h.pick,v=h.pInt,j=h.getOptions().plotOptions,k=h.seriesTypes,w=h.extendClass,l=h.wrap,
10
- q=h.Axis,F=h.Tick,y=h.Series,r=k.column.prototype,s=function(){};u(z.prototype,{init:function(a,b,c){var d=this,f=d.defaultOptions;d.chart=b;if(b.angular)f.background={};d.options=a=o(f,a);(a=a.background)&&p([].concat(h.splat(a)).reverse(),function(a){var b=a.backgroundColor,a=o(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,
11
- 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,outerRadius:"105%"}});var x=q.prototype,q=F.prototype,G={getOffset:s,redraw:function(){this.isDirty=!1},render:function(){this.isDirty=!1},setScale:s,setCategories:s,setTitle:s},E={isRadial:!0,defaultRadialGaugeOptions:{labels:{align:"center",x:0,y:null},minorGridLineWidth:0,minorTickInterval:"auto",minorTickLength:10,minorTickPosition:"inside",
8
+ (function(h,u){function z(a,b,c){this.init.call(this,a,b,c)}function A(a,b,c){a.call(this,b,c);if(this.chart.polar)this.closeSegment=function(a){var b=this.xAxis.center;a.push("L",b[0],b[1])},this.closedStacks=!0}function B(a,b){var c=this.chart,d=this.options.animation,e=this.group,g=this.markerGroup,f=this.xAxis.center,j=c.plotLeft,n=c.plotTop;if(c.polar){if(c.renderer.isSVG)if(d===!0&&(d={}),b){if(e.attrSetters.scaleX=e.attrSetters.scaleY=function(a,b){this[b]=a;this.scaleX!==u&&this.scaleY!==
9
+ u&&this.element.setAttribute("transform","translate("+this.translateX+","+this.translateY+") scale("+this.scaleX+","+this.scaleY+")");return!1},c={translateX:f[0]+j,translateY:f[1]+n,scaleX:0,scaleY:0},e.attr(c),g)g.attrSetters=e.attrSetters,g.attr(c)}else c={translateX:j,translateY:n,scaleX:1,scaleY:1},e.animate(c,d),g&&g.animate(c,d),this.animate=null}else a.call(this,b)}var p=h.each,v=h.extend,o=h.merge,D=h.map,m=h.pick,w=h.pInt,k=h.getOptions().plotOptions,i=h.seriesTypes,E=h.extendClass,l=h.wrap,
10
+ r=h.Axis,G=h.Tick,y=h.Series,q=i.column.prototype,s=function(){};v(z.prototype,{init:function(a,b,c){var d=this,e=d.defaultOptions;d.chart=b;if(b.angular)e.background={};d.options=a=o(e,a);(a=a.background)&&p([].concat(h.splat(a)).reverse(),function(a){var b=a.backgroundColor,a=o(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,
11
+ 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,outerRadius:"105%"}});var x=r.prototype,r=G.prototype,H={getOffset:s,redraw:function(){this.isDirty=!1},render:function(){this.isDirty=!1},setScale:s,setCategories:s,setTitle:s},F={isRadial:!0,defaultRadialGaugeOptions:{labels:{align:"center",x:0,y:null},minorGridLineWidth:0,minorTickInterval:"auto",minorTickLength:10,minorTickPosition:"inside",
12
12
  minorTickWidth:1,plotBands:[],tickLength:10,tickPosition:"inside",tickWidth:2,title:{rotation:0},zIndex:2},defaultRadialXOptions:{gridLineWidth:1,labels:{align:null,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=o(this.defaultOptions,this.defaultRadialOptions,a)},getOffset:function(){x.getOffset.call(this);
13
- this.chart.axisOffset[this.side]=0;this.center=this.pane.center=k.pie.prototype.getCenter.call(this.pane)},getLinePath:function(a,b){var c=this.center,b=n(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(){x.setAxisTranslation.call(this);if(this.center&&(this.transA=this.isCircular?(this.endAngleRad-this.startAngleRad)/(this.max-this.min||1):this.center[2]/2/
13
+ this.chart.axisOffset[this.side]=0;this.center=this.pane.center=i.pie.prototype.getCenter.call(this.pane)},getLinePath:function(a,b){var c=this.center,b=m(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(){x.setAxisTranslation.call(this);if(this.center&&(this.transA=this.isCircular?(this.endAngleRad-this.startAngleRad)/(this.max-this.min||1):this.center[2]/2/
14
14
  (this.max-this.min||1),this.isXAxis))this.minPixelPadding=this.transA*this.minPointOffset+(this.reversed?(this.endAngleRad-this.startAngleRad)/4:0)},beforeSetTickPositions:function(){this.autoConnect&&(this.max+=this.categories&&1||this.pointRange||this.closestPointRange)},setAxisSize:function(){x.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=
15
- this.translate(a),a=this.min;return this.postTranslate(this.translate(a),n(b,this.center[2]/2)-this.offset)},postTranslate:function(a,b){var c=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,f=this.startAngleRad,e=d[2]/2,g=[n(c.outerRadius,"100%"),c.innerRadius,n(c.thickness,10)],i=/%$/,m,C=this.isCircular;this.options.gridLineInterpolation==="polygon"?d=this.getPlotLinePath(a).concat(this.getPlotLinePath(b,
16
- !0)):(C||(g[0]=this.translate(a),g[1]=this.translate(b)),g=D(g,function(a){i.test(a)&&(a=v(a,10)*e/100);return a}),c.shape==="circle"||!C?(a=-Math.PI/2,b=Math.PI*1.5,m=!0):(a=f+this.translate(a),b=f+this.translate(b)),d=this.chart.renderer.symbols.arc(this.left+d[0],this.top+d[1],g[0],g[0],{start:a,end:b,innerR:n(g[1],g[0]-g[2]),open:m}));return d},getPlotLinePath:function(a,b){var c=this.center,d=this.chart,f=this.getPosition(a),e,g,i;this.isCircular?i=["M",c[0]+d.plotLeft,c[1]+d.plotTop,"L",f.x,
17
- f.y]:this.options.gridLineInterpolation==="circle"?(a=this.translate(a))&&(i=this.getLinePath(0,a)):(e=d.xAxis[0],i=[],a=this.translate(a),c=e.tickPositions,e.autoConnect&&(c=c.concat([c[0]])),b&&(c=[].concat(c).reverse()),p(c,function(b,c){g=e.getPosition(b,a);i.push(c?"L":"M",g.x,g.y)}));return i},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)}}};l(x,"init",function(a,
18
- b,c){var d=this,f=b.angular,e=b.polar,g=c.isX,i=f&&g,m;if(f){if(u(this,i?G:E),m=!g)this.defaultRadialOptions=this.defaultRadialGaugeOptions}else if(e)u(this,E),this.defaultRadialOptions=(m=g)?this.defaultRadialXOptions:o(this.defaultYAxisOptions,this.defaultRadialYOptions);a.call(this,b,c);if(!i&&(f||e)){a=this.options;if(!b.panes)b.panes=D(h.splat(b.options.pane),function(a){return new z(a,b,d)});this.pane=f=b.panes[c.pane||0];e=f.options;b.inverted=!1;b.options.chart.zoomType=null;this.startAngleRad=
19
- f=(e.startAngle-90)*Math.PI/180;this.endAngleRad=e=(n(e.endAngle,e.startAngle+360)-90)*Math.PI/180;this.offset=a.offset||0;if((this.isCircular=m)&&c.max===t&&e-f===2*Math.PI)this.autoConnect=!0}});l(q,"getPosition",function(a,b,c,d,f){var e=this.axis;return e.getPosition?e.getPosition(c):a.call(this,b,c,d,f)});l(q,"getLabelPosition",function(a,b,c,d,f,e,g,i,m){var h=this.axis,k=e.y,j=e.align,l=(h.translate(this.pos)+h.startAngleRad+Math.PI/2)/Math.PI*180;h.isRadial?(a=h.getPosition(this.pos,h.center[2]/
20
- 2+n(e.distance,-25)),e.rotation==="auto"?d.attr({rotation:l}):k===null&&(k=v(d.styles.lineHeight)*0.9-d.getBBox().height/2),j===null&&(j=h.isCircular?l>20&&l<160?"left":l>200&&l<340?"right":"center":"center",d.attr({align:j})),a.x+=e.x,a.y+=k):a=a.call(this,b,c,d,f,e,g,i,m);return a});l(q,"getMarkPath",function(a,b,c,d,f,e,g){var i=this.axis;i.isRadial?(a=i.getPosition(this.pos,i.center[2]/2+d),b=["M",b,c,"L",a.x,a.y]):b=a.call(this,b,c,d,f,e,g);return b});j.arearange=o(j.area,{lineWidth:1,marker:null,
21
- threshold:null,tooltip:{pointFormat:'<span style="color:{series.color}">{series.name}</span>: <b>{point.low}</b> - <b>{point.high}</b><br/>'},trackByArea:!0,dataLabels:{xLow:0,xHigh:0,yLow:16,yHigh:-6},shadow:!1});q=h.extendClass(h.Point,{applyOptions:function(a,b){var c=this.series,d=c.pointArrayMap,f=0,e=0,g=d.length;if(typeof a==="object"&&typeof a.length!=="number")u(this,a),this.options=a;else if(a.length){if(a.length>g){if(typeof a[0]==="string")this.name=a[0];else if(typeof a[0]==="number")this.x=
22
- a[0];f++}for(;e<g;)this[d[e++]]=a[f++]}this.y=this[c.pointValKey];if(this.x===t&&c)this.x=b===t?c.autoIncrement():b;return this},toYData:function(){return[this.low,this.high]}});k.arearange=h.extendClass(k.area,{type:"arearange",pointArrayMap:["low","high"],pointClass:q,pointValKey:"low",translate:function(){var a=this.yAxis;k.area.prototype.translate.apply(this);p(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){for(var b=
23
- [],c=a.length,d=y.prototype.getSegmentPath,f;c--;)f=a[c],b.push({plotX:f.plotX,plotY:f.plotHigh});a=d.call(this,a);d=d.call(this,b);b=[].concat(a,d);d[0]="L";this.areaPath=this.areaPath.concat(a,d);return b},drawDataLabels:function(){var a=this.data,b=a.length,c,d=[],f=y.prototype,e=this.options.dataLabels,g,i=this.chart.inverted;if(e.enabled||this._hasPointLabels){for(c=b;c--;)g=a[c],g.y=g.high,g.plotY=g.plotHigh,d[c]=g.dataLabel,g.dataLabel=g.dataLabelUpper,i?(e.align="left",e.x=e.xHigh):e.y=e.yHigh;
24
- f.drawDataLabels.apply(this,arguments);for(c=b;c--;)g=a[c],g.dataLabelUpper=g.dataLabel,g.dataLabel=d[c],g.y=g.low,g.plotY=g.plotLow,i?(e.align="right",e.x=e.xLow):e.y=e.yLow;f.drawDataLabels.apply(this,arguments)}},getSymbol:k.column.prototype.getSymbol,drawPoints:s});j.areasplinerange=o(j.arearange);k.areasplinerange=w(k.arearange,{type:"areasplinerange",getPointSpline:k.spline.prototype.getPointSpline});j.columnrange=o(j.column,j.arearange,{lineWidth:1,pointRange:null});k.columnrange=w(k.arearange,
25
- {type:"columnrange",translate:function(){var a=this.yAxis,b;r.translate.apply(this);p(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;c.trackerArgs=d})},drawGraph:s,pointAttrToOptions:r.pointAttrToOptions,drawPoints:r.drawPoints,drawTracker:r.drawTracker,animate:r.animate});j.gauge=o(j.line,{dataLabels:{enabled:!0,y:30,borderWidth:1,borderColor:"silver",borderRadius:3,style:{fontWeight:"bold"}},dial:{},pivot:{},tooltip:{headerFormat:""},
26
- showInLegend:!1});j={type:"gauge",pointClass:h.extendClass(h.Point,{setState:function(a){this.state=a}}),angular:!0,translate:function(){var a=this,b=a.yAxis,c=b.center;a.generatePoints();p(a.points,function(d){var f=o(a.options.dial,d.dial),e=v(n(f.radius,80))*c[2]/200,g=v(n(f.baseLength,70))*e/100,i=v(n(f.rearLength,10))*e/100,m=f.baseWidth||3,h=f.topWidth||1;d.shapeType="path";d.shapeArgs={d:f.path||["M",-i,-m/2,"L",g,-m/2,e,-h/2,e,h/2,g,m/2,-i,m/2,"z"],translateX:c[0],translateY:c[1],rotation:(b.startAngleRad+
27
- b.translate(d.y))*180/Math.PI};d.plotX=c[0];d.plotY=c[1]})},drawPoints:function(){var a=this,b=a.yAxis.center,c=a.pivot,d=a.options,f=d.pivot,e=d.dial;p(a.points,function(b){var c=b.graphic,d=b.shapeArgs,f=d.d;c?(c.animate(d),d.d=f):b.graphic=a.chart.renderer[b.shapeType](d).attr({stroke:e.borderColor||"none","stroke-width":e.borderWidth||0,fill:e.backgroundColor||"black",rotation:d.rotation}).add(a.group)});c?c.animate({cx:b[0],cy:b[1]}):a.pivot=a.chart.renderer.circle(b[0],b[1],n(f.radius,5)).attr({"stroke-width":f.borderWidth||
28
- 0,stroke:f.borderColor||"silver",fill:f.backgroundColor||"black"}).add(a.group)},animate:function(){var a=this;p(a.points,function(b){var c=b.graphic;c&&(c.attr({rotation:a.yAxis.startAngleRad*180/Math.PI}),c.animate({rotation:b.shapeArgs.rotation},a.options.animation))});a.animate=null},render:function(){this.group=this.plotGroup("group","series",this.visible?"visible":"hidden",this.options.zIndex,this.chart.seriesGroup);k.pie.prototype.render.call(this);this.group.clip(this.chart.clipRect)},setData:k.pie.prototype.setData,
29
- drawTracker:k.column.prototype.drawTracker};k.gauge=h.extendClass(k.line,j);j=y.prototype;w=h.MouseTracker.prototype;j.toXY=function(a){var b,c=this.chart;b=a.plotX;var d=a.plotY;a.rectPlotX=b;a.rectPlotY=d;a.deg=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};l(k.area.prototype,"init",A);l(k.areaspline.prototype,"init",A);l(k.spline.prototype,"getPointSpline",function(a,b,c,d){var f,e,g,i,h,k,j;if(this.chart.polar){f=
30
- c.plotX;e=c.plotY;a=b[d-1];g=b[d+1];this.connectEnds&&(a||(a=b[b.length-2]),g||(g=b[1]));if(a&&g)i=a.plotX,h=a.plotY,b=g.plotX,k=g.plotY,i=(1.5*f+i)/2.5,h=(1.5*e+h)/2.5,g=(1.5*f+b)/2.5,j=(1.5*e+k)/2.5,b=Math.sqrt(Math.pow(i-f,2)+Math.pow(h-e,2)),k=Math.sqrt(Math.pow(g-f,2)+Math.pow(j-e,2)),i=Math.atan2(h-e,i-f),h=Math.atan2(j-e,g-f),j=Math.PI/2+(i+h)/2,Math.abs(i-j)>Math.PI/2&&(j-=Math.PI),i=f+Math.cos(j)*b,h=e+Math.sin(j)*b,g=f+Math.cos(Math.PI+j)*k,j=e+Math.sin(Math.PI+j)*k,c.rightContX=g,c.rightContY=
31
- j;d?(c=["C",a.rightContX||a.plotX,a.rightContY||a.plotY,i||f,h||e,f,e],a.rightContX=a.rightContY=null):c=["M",f,e]}else c=a.call(this,b,c,d);return c});l(j,"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])});l(j,"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,
32
- b)});l(j,"animate",B);l(r,"animate",B);l(j,"setTooltipPoints",function(a,b){this.chart.polar&&u(this.xAxis,{tooltipLen:360,tooltipPosName:"deg"});return a.call(this,b)});l(r,"translate",function(a){var b=this.xAxis,c=this.yAxis.len,d=b.center,f=b.startAngleRad,e=this.chart.renderer,g;this.preventPostTranslate=!0;a.call(this);if(b.isRadial){a=this.points;for(g=a.length;g--;)b=a[g],b.shapeType="path",b.shapeArgs={d:e.symbols.arc(d[0],d[1],c-b.plotY,null,{start:f+b.barX,end:f+b.barX+b.pointWidth,innerR:c-
33
- n(b.yBottom,c)})},this.toXY(b)}});l(w,"getIndex",function(a,b){var c,d=this.chart,f;d.polar?(f=d.xAxis[0].center,c=b.chartX-f[0]-d.plotLeft,d=b.chartY-f[1]-d.plotTop,c=180-Math.round(Math.atan2(c,d)/Math.PI*180)):c=a.call(this,b);return c});l(w,"getMouseCoordinates",function(a,b){var c=this.chart,d={xAxis:[],yAxis:[]};c.polar?p(c.axes,function(a){var e=a.isXAxis,g=a.center,h=b.chartX-g[0]-c.plotLeft,g=b.chartY-g[1]-c.plotTop;d[e?"xAxis":"yAxis"].push({axis:a,value:a.translate(e?Math.PI-Math.atan2(h,
34
- g):Math.sqrt(Math.pow(h,2)+Math.pow(g,2)),!0)})}):d=a.call(this,b);return d})})(Highcharts);
15
+ this.translate(a),a=this.min;return this.postTranslate(this.translate(a),m(b,this.center[2]/2)-this.offset)},postTranslate:function(a,b){var c=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=[m(c.outerRadius,"100%"),c.innerRadius,m(c.thickness,10)],j=/%$/,n,C=this.isCircular;this.options.gridLineInterpolation==="polygon"?d=this.getPlotLinePath(a).concat(this.getPlotLinePath(b,
16
+ !0)):(C||(f[0]=this.translate(a),f[1]=this.translate(b)),f=D(f,function(a){j.test(a)&&(a=w(a,10)*g/100);return a}),c.shape==="circle"||!C?(a=-Math.PI/2,b=Math.PI*1.5,n=!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:m(f[1],f[0]-f[2]),open:n}));return d},getPlotLinePath:function(a,b){var c=this.center,d=this.chart,e=this.getPosition(a),g,f,j;this.isCircular?j=["M",c[0]+d.plotLeft,c[1]+d.plotTop,"L",e.x,
17
+ e.y]:this.options.gridLineInterpolation==="circle"?(a=this.translate(a))&&(j=this.getLinePath(0,a)):(g=d.xAxis[0],j=[],a=this.translate(a),c=g.tickPositions,g.autoConnect&&(c=c.concat([c[0]])),b&&(c=[].concat(c).reverse()),p(c,function(b,c){f=g.getPosition(b,a);j.push(c?"L":"M",f.x,f.y)}));return j},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)}}};l(x,"init",function(a,
18
+ b,c){var d=this,e=b.angular,g=b.polar,f=c.isX,j=e&&f,n;if(e){if(v(this,j?H:F),n=!f)this.defaultRadialOptions=this.defaultRadialGaugeOptions}else if(g)v(this,F),this.defaultRadialOptions=(n=f)?this.defaultRadialXOptions:o(this.defaultYAxisOptions,this.defaultRadialYOptions);a.call(this,b,c);if(!j&&(e||g)){a=this.options;if(!b.panes)b.panes=D(h.splat(b.options.pane),function(a){return new z(a,b,d)});this.pane=e=b.panes[c.pane||0];g=e.options;b.inverted=!1;b.options.chart.zoomType=null;this.startAngleRad=
19
+ e=(g.startAngle-90)*Math.PI/180;this.endAngleRad=g=(m(g.endAngle,g.startAngle+360)-90)*Math.PI/180;this.offset=a.offset||0;if((this.isCircular=n)&&c.max===u&&g-e===2*Math.PI)this.autoConnect=!0}});l(r,"getPosition",function(a,b,c,d,e){var g=this.axis;return g.getPosition?g.getPosition(c):a.call(this,b,c,d,e)});l(r,"getLabelPosition",function(a,b,c,d,e,g,f,j,n){var h=this.axis,i=g.y,l=g.align,k=(h.translate(this.pos)+h.startAngleRad+Math.PI/2)/Math.PI*180;h.isRadial?(a=h.getPosition(this.pos,h.center[2]/
20
+ 2+m(g.distance,-25)),g.rotation==="auto"?d.attr({rotation:k}):i===null&&(i=w(d.styles.lineHeight)*0.9-d.getBBox().height/2),l===null&&(l=h.isCircular?k>20&&k<160?"left":k>200&&k<340?"right":"center":"center",d.attr({align:l})),a.x+=g.x,a.y+=i):a=a.call(this,b,c,d,e,g,f,j,n);return a});l(r,"getMarkPath",function(a,b,c,d,e,g,f){var j=this.axis;j.isRadial?(a=j.getPosition(this.pos,j.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});k.arearange=o(k.area,{lineWidth:1,marker:null,
21
+ threshold:null,tooltip:{pointFormat:'<span style="color:{series.color}">{series.name}</span>: <b>{point.low}</b> - <b>{point.high}</b><br/>'},trackByArea:!0,dataLabels:{verticalAlign:null,xLow:0,xHigh:0,yLow:0,yHigh:0},shadow:!1});r=h.extendClass(h.Point,{applyOptions:function(a,b){var c=this.series,d=c.pointArrayMap,e=0,g=0,f=d.length;if(typeof a==="object"&&typeof a.length!=="number")v(this,a),this.options=a;else if(a.length){if(a.length>f){if(typeof a[0]==="string")this.name=a[0];else if(typeof a[0]===
22
+ "number")this.x=a[0];e++}for(;g<f;)this[d[g++]]=a[e++]}this.y=this[c.pointValKey];if(this.x===u&&c)this.x=b===u?c.autoIncrement():b;return this},toYData:function(){return[this.low,this.high]}});i.arearange=h.extendClass(i.area,{type:"arearange",pointArrayMap:["low","high"],pointClass:r,pointValKey:"low",translate:function(){var a=this.yAxis;i.area.prototype.translate.apply(this);p(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){for(var b=
23
+ [],c=a.length,d=y.prototype.getSegmentPath,e;c--;)e=a[c],b.push({plotX:e.plotX,plotY:e.plotHigh});a=d.call(this,a);d=d.call(this,b);b=[].concat(a,d);d[0]="L";this.areaPath=this.areaPath.concat(a,d);return b},drawDataLabels:function(){var a=this.data,b=a.length,c,d=[],e=y.prototype,g=this.options.dataLabels,f,j=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,f.below=!1,j?(g.align="left",g.x=g.xHigh):
24
+ 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,j?(g.align="right",g.x=g.xLow):g.y=g.yLow;e.drawDataLabels.apply(this,arguments)}},alignDataLabel:i.column.prototype.alignDataLabel,getSymbol:i.column.prototype.getSymbol,drawPoints:s});k.areasplinerange=o(k.arearange);i.areasplinerange=E(i.arearange,{type:"areasplinerange",getPointSpline:i.spline.prototype.getPointSpline});k.columnrange=o(k.column,
25
+ k.arearange,{lineWidth:1,pointRange:null});i.columnrange=E(i.arearange,{type:"columnrange",translate:function(){var a=this.yAxis,b;q.translate.apply(this);p(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;c.trackerArgs=d})},drawGraph:s,pointAttrToOptions:q.pointAttrToOptions,drawPoints:q.drawPoints,drawTracker:q.drawTracker,animate:q.animate});k.gauge=o(k.line,{dataLabels:{enabled:!0,y:15,borderWidth:1,borderColor:"silver",
26
+ borderRadius:3,style:{fontWeight:"bold"},verticalAlign:"top"},dial:{},pivot:{},tooltip:{headerFormat:""},showInLegend:!1});k={type:"gauge",pointClass:h.extendClass(h.Point,{setState:function(a){this.state=a}}),angular:!0,translate:function(){var a=this,b=a.yAxis,c=b.center;a.generatePoints();p(a.points,function(d){var e=o(a.options.dial,d.dial),g=w(m(e.radius,80))*c[2]/200,f=w(m(e.baseLength,70))*g/100,j=w(m(e.rearLength,10))*g/100,h=e.baseWidth||3,i=e.topWidth||1;d.shapeType="path";d.shapeArgs={d:e.path||
27
+ ["M",-j,-h/2,"L",f,-h/2,g,-i/2,g,i/2,f,h/2,-j,h/2,"z"],translateX:c[0],translateY:c[1],rotation:(b.startAngleRad+b.translate(d.y))*180/Math.PI};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;p(a.points,function(b){var c=b.graphic,e=b.shapeArgs,h=e.d,i=o(d.dial,b.dial);c?(c.animate(e),e.d=h):b.graphic=a.chart.renderer[b.shapeType](e).attr({stroke:i.borderColor||"none","stroke-width":i.borderWidth||0,fill:i.backgroundColor||"black",rotation:e.rotation}).add(a.group)});
28
+ c?c.animate({cx:b[0],cy:b[1]}):a.pivot=a.chart.renderer.circle(b[0],b[1],m(e.radius,5)).attr({"stroke-width":e.borderWidth||0,stroke:e.borderColor||"silver",fill:e.backgroundColor||"black"}).add(a.group)},animate:function(){var a=this;p(a.points,function(b){var c=b.graphic;c&&(c.attr({rotation:a.yAxis.startAngleRad*180/Math.PI}),c.animate({rotation:b.shapeArgs.rotation},a.options.animation))});a.animate=null},render:function(){this.group=this.plotGroup("group","series",this.visible?"visible":"hidden",
29
+ this.options.zIndex,this.chart.seriesGroup);i.pie.prototype.render.call(this);this.group.clip(this.chart.clipRect)},setData:i.pie.prototype.setData,drawTracker:i.column.prototype.drawTracker};i.gauge=h.extendClass(i.line,k);var t=y.prototype,k=h.MouseTracker.prototype;t.toXY=function(a){var b,c=this.chart;b=a.plotX;var d=a.plotY;a.rectPlotX=b;a.rectPlotY=d;a.deg=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};
30
+ l(i.area.prototype,"init",A);l(i.areaspline.prototype,"init",A);l(i.spline.prototype,"getPointSpline",function(a,b,c,d){var e,g,f,j,h,i,k;if(this.chart.polar){e=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)j=a.plotX,h=a.plotY,b=f.plotX,i=f.plotY,j=(1.5*e+j)/2.5,h=(1.5*g+h)/2.5,f=(1.5*e+b)/2.5,k=(1.5*g+i)/2.5,b=Math.sqrt(Math.pow(j-e,2)+Math.pow(h-g,2)),i=Math.sqrt(Math.pow(f-e,2)+Math.pow(k-g,2)),j=Math.atan2(h-g,j-e),h=Math.atan2(k-g,f-e),k=Math.PI/
31
+ 2+(j+h)/2,Math.abs(j-k)>Math.PI/2&&(k-=Math.PI),j=e+Math.cos(k)*b,h=g+Math.sin(k)*b,f=e+Math.cos(Math.PI+k)*i,k=g+Math.sin(Math.PI+k)*i,c.rightContX=f,c.rightContY=k;d?(c=["C",a.rightContX||a.plotX,a.rightContY||a.plotY,j||e,h||g,e,g],a.rightContX=a.rightContY=null):c=["M",e,g]}else c=a.call(this,b,c,d);return c});l(t,"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])});l(t,"getSegmentPath",function(a,b){var c=
32
+ 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,b)});l(t,"animate",B);l(q,"animate",B);l(t,"setTooltipPoints",function(a,b){this.chart.polar&&v(this.xAxis,{tooltipLen:360,tooltipPosName:"deg"});return a.call(this,b)});l(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=
33
+ 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-m(f.yBottom,c)})},this.toXY(f)}});l(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";t.alignDataLabel.call(this,b,c,d,e,g)}else a.call(this,
34
+ b,c,d,e,g)});l(k,"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,d)/Math.PI*180)):c=a.call(this,b);return c});l(k,"getMouseCoordinates",function(a,b){var c=this.chart,d={xAxis:[],yAxis:[]};c.polar?p(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,
35
+ 2)+Math.pow(f,2)),!0)})}):d=a.call(this,b);return d})})(Highcharts);
@@ -2,7 +2,7 @@
2
2
  // @compilation_level SIMPLE_OPTIMIZATIONS
3
3
 
4
4
  /**
5
- * @license Highcharts JS v2.3.2 (2012-08-31)
5
+ * @license Highcharts JS v2.3.3 (2012-10-04)
6
6
  *
7
7
  * (c) 2009-2011 Torstein Hønsi
8
8
  *
@@ -1258,8 +1258,10 @@ pathAnim = {
1258
1258
  var ret = e.originalEvent || e;
1259
1259
 
1260
1260
  // computed by jQuery, needed by IE8
1261
- ret.pageX = e.pageX;
1262
- ret.pageY = e.pageY;
1261
+ if (ret.pageX === UNDEFINED) { // #1236
1262
+ ret.pageX = e.pageX;
1263
+ ret.pageY = e.pageY;
1264
+ }
1263
1265
 
1264
1266
  return ret;
1265
1267
  },
@@ -1360,8 +1362,8 @@ defaultOptions = {
1360
1362
  },
1361
1363
  global: {
1362
1364
  useUTC: true,
1363
- canvasToolsURL: 'http://code.highcharts.com/2.3.2/modules/canvas-tools.js',
1364
- VMLRadialGradientURL: 'http://code.highcharts.com/2.3.2/gfx/vml-radial-gradient.png'
1365
+ canvasToolsURL: 'http://code.highcharts.com/2.3.3/modules/canvas-tools.js',
1366
+ VMLRadialGradientURL: 'http://code.highcharts.com/2.3.3/gfx/vml-radial-gradient.png'
1365
1367
  },
1366
1368
  chart: {
1367
1369
  //animation: true,
@@ -1475,10 +1477,11 @@ defaultOptions = {
1475
1477
  },
1476
1478
  dataLabels: merge(defaultLabelOptions, {
1477
1479
  enabled: false,
1478
- y: -6,
1479
1480
  formatter: function () {
1480
1481
  return this.y;
1481
- }
1482
+ },
1483
+ verticalAlign: 'bottom', // above singular point
1484
+ y: 0
1482
1485
  // backgroundColor: undefined,
1483
1486
  // borderColor: undefined,
1484
1487
  // borderRadius: undefined,
@@ -1867,7 +1870,7 @@ SVGElement.prototype = {
1867
1870
  i,
1868
1871
  child,
1869
1872
  element = wrapper.element,
1870
- nodeName = element.nodeName,
1873
+ nodeName = element.nodeName.toLowerCase(), // Android2 requires lower for "text"
1871
1874
  renderer = wrapper.renderer,
1872
1875
  skipAttr,
1873
1876
  titleNode,
@@ -2154,7 +2157,7 @@ SVGElement.prototype = {
2154
2157
  /*jslint unparam: true*//* allow unused param a in the regexp function below */
2155
2158
  var elemWrapper = this,
2156
2159
  elem = elemWrapper.element,
2157
- textWidth = styles && styles.width && elem.nodeName === 'text',
2160
+ textWidth = styles && styles.width && elem.nodeName.toLowerCase() === 'text',
2158
2161
  n,
2159
2162
  serializedCss = '',
2160
2163
  hyphenate = function (a, b) { return '-' + b.toLowerCase(); };
@@ -2174,6 +2177,12 @@ SVGElement.prototype = {
2174
2177
  // store object
2175
2178
  elemWrapper.styles = styles;
2176
2179
 
2180
+
2181
+ // Don't handle line wrap on canvas
2182
+ if (useCanVG && textWidth) {
2183
+ delete styles.width;
2184
+ }
2185
+
2177
2186
  // serialize and set style attribute
2178
2187
  if (isIE && !hasSVG) { // legacy IE doesn't support setting style attribute
2179
2188
  if (textWidth) {
@@ -2364,15 +2373,15 @@ SVGElement.prototype = {
2364
2373
  yCorr = wrapper.yCorr || 0,
2365
2374
  currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(','),
2366
2375
  rotationStyle = {},
2367
- prefix;
2376
+ cssTransformKey;
2368
2377
 
2369
2378
  if (currentTextTransform !== wrapper.cTT) { // do the calculations and DOM access only if properties changed
2370
2379
 
2371
2380
  if (defined(rotation)) {
2372
2381
 
2373
2382
  if (renderer.isSVG) { // #916
2374
- prefix = isIE ? '-ms' : isWebKit ? '-webkit' : isFirefox ? '-moz' : isOpera ? '-o' : '';
2375
- rotationStyle[prefix + '-transform'] = rotationStyle.transform = 'rotate(' + rotation + 'deg)';
2383
+ cssTransformKey = isIE ? '-ms-transform' : isWebKit ? '-webkit-transform' : isFirefox ? 'MozTransform' : isOpera ? '-o-transform' : '';
2384
+ rotationStyle[cssTransformKey] = rotationStyle.transform = 'rotate(' + rotation + 'deg)';
2376
2385
 
2377
2386
  } else {
2378
2387
  radians = rotation * deg2rad; // deg to rad
@@ -2388,7 +2397,6 @@ SVGElement.prototype = {
2388
2397
  ', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta,
2389
2398
  ', sizingMethod=\'auto expand\')'].join('') : NONE;
2390
2399
  }
2391
-
2392
2400
  css(elem, rotationStyle);
2393
2401
  }
2394
2402
 
@@ -2519,7 +2527,7 @@ SVGElement.prototype = {
2519
2527
 
2520
2528
 
2521
2529
  // align
2522
- if (/^(right|center)$/.test(align)) {
2530
+ if (align === 'right' || align === 'center') {
2523
2531
  x += (box.width - (alignOptions.width || 0)) /
2524
2532
  { right: 1, center: 2 }[align];
2525
2533
  }
@@ -2527,7 +2535,7 @@ SVGElement.prototype = {
2527
2535
 
2528
2536
 
2529
2537
  // vertical align
2530
- if (/^(bottom|middle)$/.test(vAlign)) {
2538
+ if (vAlign === 'bottom' || vAlign === 'middle') {
2531
2539
  y += (box.height - (alignOptions.height || 0)) /
2532
2540
  ({ bottom: 1, middle: 2 }[vAlign] || 1);
2533
2541
 
@@ -2553,6 +2561,7 @@ SVGElement.prototype = {
2553
2561
  height,
2554
2562
  rotation = wrapper.rotation,
2555
2563
  element = wrapper.element,
2564
+ styles = wrapper.styles,
2556
2565
  rad = rotation * deg2rad;
2557
2566
 
2558
2567
  if (!bBox) {
@@ -2598,6 +2607,11 @@ SVGElement.prototype = {
2598
2607
  }
2599
2608
  }
2600
2609
 
2610
+ // Workaround for wrong bounding box in IE9 and IE10 (#1101)
2611
+ if (isIE && styles && styles.fontSize === '11px' && height === 22.700000762939453) {
2612
+ bBox.height = 14;
2613
+ }
2614
+
2601
2615
  wrapper.bBox = bBox;
2602
2616
  }
2603
2617
  return bBox;
@@ -2704,7 +2718,6 @@ SVGElement.prototype = {
2704
2718
  var wrapper = this,
2705
2719
  element = wrapper.element || {},
2706
2720
  shadows = wrapper.shadows,
2707
- box = wrapper.box,
2708
2721
  key,
2709
2722
  i;
2710
2723
 
@@ -2734,11 +2747,6 @@ SVGElement.prototype = {
2734
2747
  });
2735
2748
  }
2736
2749
 
2737
- // destroy label box
2738
- if (box) {
2739
- box.destroy();
2740
- }
2741
-
2742
2750
  // remove from alignObjects
2743
2751
  erase(wrapper.renderer.alignedObjects, wrapper);
2744
2752
 
@@ -2784,7 +2792,7 @@ SVGElement.prototype = {
2784
2792
  shadowElementOpacity = (shadowOptions.opacity || 0.15) / shadowWidth;
2785
2793
  transform = this.parentInverted ?
2786
2794
  '(-1,-1)' :
2787
- '(' + (shadowOptions.offsetX || 1) + ', ' + (shadowOptions.offsetY || 1) + ')';
2795
+ '(' + pick(shadowOptions.offsetX, 1) + ', ' + pick(shadowOptions.offsetY, 1) + ')';
2788
2796
  for (i = 1; i <= shadowWidth; i++) {
2789
2797
  shadow = element.cloneNode(0);
2790
2798
  strokeWidth = (shadowWidth * 2) + 1 - (2 * i);
@@ -2965,13 +2973,13 @@ SVGRenderer.prototype = {
2965
2973
  hrefRegex = /href="([^"]+)"/,
2966
2974
  parentX = attr(textNode, 'x'),
2967
2975
  textStyles = wrapper.styles,
2968
- width = textStyles && pInt(textStyles.width),
2976
+ width = textStyles && textStyles.width && pInt(textStyles.width),
2969
2977
  textLineHeight = textStyles && textStyles.lineHeight,
2970
2978
  lastLine,
2971
2979
  GET_COMPUTED_STYLE = 'getComputedStyle',
2972
2980
  i = childNodes.length,
2973
2981
  linePositions = [];
2974
-
2982
+
2975
2983
  // Needed in IE9 because it doesn't report tspan's offsetHeight (#893)
2976
2984
  function getLineHeightByBBox(lineNo) {
2977
2985
  linePositions[lineNo] = textNode.getBBox ?
@@ -3004,13 +3012,11 @@ SVGRenderer.prototype = {
3004
3012
  each(spans, function (span) {
3005
3013
  if (span !== '' || spans.length === 1) {
3006
3014
  var attributes = {},
3007
- tspan = doc.createElementNS(SVG_NS, 'tspan');
3015
+ tspan = doc.createElementNS(SVG_NS, 'tspan'),
3016
+ spanStyle; // #390
3008
3017
  if (styleRegex.test(span)) {
3009
- attr(
3010
- tspan,
3011
- 'style',
3012
- span.match(styleRegex)[1].replace(/(;| |^)color([ :])/, '$1fill$2')
3013
- );
3018
+ spanStyle = span.match(styleRegex)[1].replace(/(;| |^)color([ :])/, '$1fill$2');
3019
+ attr(tspan, 'style', spanStyle);
3014
3020
  }
3015
3021
  if (hrefRegex.test(span)) {
3016
3022
  attr(tspan, 'onclick', 'location.href=\"' + span.match(hrefRegex)[1] + '\"');
@@ -3073,7 +3079,7 @@ SVGRenderer.prototype = {
3073
3079
 
3074
3080
  // check width and apply soft breaks
3075
3081
  if (width) {
3076
- var words = span.replace(/-/g, '- ').split(' '),
3082
+ var words = span.replace(/([^\^])-/g, '$1- ').split(' '), // #1273
3077
3083
  tooLong,
3078
3084
  actualWidth,
3079
3085
  rest = [];
@@ -3091,6 +3097,9 @@ SVGRenderer.prototype = {
3091
3097
  dy: textLineHeight || 16,
3092
3098
  x: parentX
3093
3099
  });
3100
+ if (spanStyle) { // #390
3101
+ attr(tspan, 'style', spanStyle);
3102
+ }
3094
3103
  textNode.appendChild(tspan);
3095
3104
 
3096
3105
  if (actualWidth > width) { // a single word is pressing it out
@@ -3724,6 +3733,7 @@ SVGRenderer.prototype = {
3724
3733
  // declare variables
3725
3734
  var renderer = this,
3726
3735
  defaultChartStyle = defaultOptions.chart.style,
3736
+ fakeSVG = useCanVG || (!hasSVG && renderer.forExport),
3727
3737
  wrapper;
3728
3738
 
3729
3739
  if (useHTML && !renderer.forExport) {
@@ -3745,7 +3755,7 @@ SVGRenderer.prototype = {
3745
3755
  });
3746
3756
 
3747
3757
  // Prevent wrapping from creating false offsetWidths in export in legacy IE (#1079, #1063)
3748
- if (!hasSVG && renderer.forExport) {
3758
+ if (fakeSVG) {
3749
3759
  wrapper.css({
3750
3760
  position: ABSOLUTE
3751
3761
  });
@@ -4152,9 +4162,11 @@ SVGRenderer.prototype = {
4152
4162
  removeEvent(wrapper.element, 'mouseleave');
4153
4163
 
4154
4164
  if (text) {
4155
- // Destroy the text element
4156
4165
  text = text.destroy();
4157
4166
  }
4167
+ if (box) {
4168
+ box = box.destroy();
4169
+ }
4158
4170
  // Call base implementation to destroy the rest
4159
4171
  SVGElement.prototype.destroy.call(wrapper);
4160
4172
  }
@@ -4642,8 +4654,8 @@ var VMLElement = {
4642
4654
 
4643
4655
  shadow = createElement(renderer.prepVML(markup),
4644
4656
  null, {
4645
- left: pInt(elemStyle.left) + (shadowOptions.offsetX || 1),
4646
- top: pInt(elemStyle.top) + (shadowOptions.offsetY || 1)
4657
+ left: pInt(elemStyle.left) + pick(shadowOptions.offsetX, 1),
4658
+ top: pInt(elemStyle.top) + pick(shadowOptions.offsetY, 1)
4647
4659
  }
4648
4660
  );
4649
4661
  if (cutOff) {
@@ -5062,9 +5074,9 @@ var VMLRendererExtension = { // inherit SVGRenderer
5062
5074
  .attr({ src: src });
5063
5075
 
5064
5076
  if (arguments.length > 1) {
5065
- obj.css({
5066
- left: x,
5067
- top: y,
5077
+ obj.attr({
5078
+ x: x,
5079
+ y: y,
5068
5080
  width: width,
5069
5081
  height: height
5070
5082
  });
@@ -5289,7 +5301,8 @@ if (useCanVG) {
5289
5301
  * together with the canvg library.
5290
5302
  */
5291
5303
  CanVGRenderer = function () {
5292
- // Empty constructor
5304
+ // Override the global SVG namespace to fake SVG/HTML that accepts CSS
5305
+ SVG_NS = 'http://www.w3.org/1999/xhtml';
5293
5306
  };
5294
5307
 
5295
5308
  /**
@@ -5908,7 +5921,8 @@ PlotLineOrBand.prototype = {
5908
5921
  /**
5909
5922
  * The class for stack items
5910
5923
  */
5911
- function StackItem(axis, options, isNegative, x, stackOption) {
5924
+ function StackItem(axis, options, isNegative, x, stackOption, stacking) {
5925
+
5912
5926
  var inverted = axis.chart.inverted;
5913
5927
 
5914
5928
  this.axis = axis;
@@ -5922,8 +5936,9 @@ function StackItem(axis, options, isNegative, x, stackOption) {
5922
5936
  // Save the x value to be able to position the label later
5923
5937
  this.x = x;
5924
5938
 
5925
- // Save the stack option on the series configuration object
5939
+ // Save the stack option on the series configuration object, and whether to treat it as percent
5926
5940
  this.stack = stackOption;
5941
+ this.percent = stacking === 'percent';
5927
5942
 
5928
5943
  // The align options and text align varies on whether the stack is negative and
5929
5944
  // if the chart is inverted or not.
@@ -5966,9 +5981,11 @@ StackItem.prototype = {
5966
5981
  this.label =
5967
5982
  this.axis.chart.renderer.text(str, 0, 0) // dummy positions, actual position updated with setOffset method in columnseries
5968
5983
  .css(this.options.style) // apply style
5969
- .attr({align: this.textAlign, // fix the text-anchor
5984
+ .attr({
5985
+ align: this.textAlign, // fix the text-anchor
5970
5986
  rotation: this.options.rotation, // rotation
5971
- visibility: HIDDEN }) // hidden until setOffset is called
5987
+ visibility: HIDDEN // hidden until setOffset is called
5988
+ })
5972
5989
  .add(group); // add to the labels-group
5973
5990
  }
5974
5991
  },
@@ -5982,24 +5999,31 @@ StackItem.prototype = {
5982
5999
  chart = axis.chart,
5983
6000
  inverted = chart.inverted,
5984
6001
  neg = this.isNegative, // special treatment is needed for negative stacks
5985
- y = axis.translate(this.total, 0, 0, 0, 1), // stack value translated mapped to chart coordinates
6002
+ y = axis.translate(this.percent ? 100 : this.total, 0, 0, 0, 1), // stack value translated mapped to chart coordinates
5986
6003
  yZero = axis.translate(0), // stack origin
5987
6004
  h = mathAbs(y - yZero), // stack height
5988
6005
  x = chart.xAxis[0].translate(this.x) + xOffset, // stack x position
5989
6006
  plotHeight = chart.plotHeight,
5990
6007
  stackBox = { // this is the box for the complete stack
5991
- x: inverted ? (neg ? y : y - h) : x,
5992
- y: inverted ? plotHeight - x - xWidth : (neg ? (plotHeight - y - h) : plotHeight - y),
5993
- width: inverted ? h : xWidth,
5994
- height: inverted ? xWidth : h
5995
- };
5996
-
5997
- if (this.label) {
5998
- this.label
5999
- .align(this.alignOptions, null, stackBox) // align the label to the box
6000
- .attr({visibility: VISIBLE}); // set visibility
6001
- }
6008
+ x: inverted ? (neg ? y : y - h) : x,
6009
+ y: inverted ? plotHeight - x - xWidth : (neg ? (plotHeight - y - h) : plotHeight - y),
6010
+ width: inverted ? h : xWidth,
6011
+ height: inverted ? xWidth : h
6012
+ },
6013
+ label = this.label,
6014
+ alignAttr;
6002
6015
 
6016
+ if (label) {
6017
+ label.align(this.alignOptions, null, stackBox); // align the label to the box
6018
+
6019
+ // Set visibility (#678)
6020
+ alignAttr = label.alignAttr;
6021
+ label.attr({
6022
+ visibility: this.options.crop === false || chart.isInsidePlot(alignAttr.x, alignAttr.y) ?
6023
+ (hasSVG ? 'inherit' : VISIBLE) :
6024
+ HIDDEN
6025
+ });
6026
+ }
6003
6027
  }
6004
6028
  };
6005
6029
  /**
@@ -6511,44 +6535,41 @@ Axis.prototype = {
6511
6535
  for (i = 0; i < yDataLength; i++) {
6512
6536
  x = xData[i];
6513
6537
  y = yData[i];
6514
- if (y !== null && y !== UNDEFINED) {
6515
-
6516
- // read stacked values into a stack based on the x value,
6517
- // the sign of y and the stack key
6518
- if (stacking) {
6519
- isNegative = y < threshold;
6520
- pointStack = isNegative ? negPointStack : posPointStack;
6521
- key = isNegative ? negKey : stackKey;
6522
-
6523
- y = pointStack[x] =
6524
- defined(pointStack[x]) ?
6525
- pointStack[x] + y : y;
6526
-
6527
-
6528
- // add the series
6529
- if (!stacks[key]) {
6530
- stacks[key] = {};
6531
- }
6532
-
6533
- // If the StackItem is there, just update the values,
6534
- // if not, create one first
6535
- if (!stacks[key][x]) {
6536
- stacks[key][x] = new StackItem(axis, axis.options.stackLabels, isNegative, x, stackOption);
6537
- }
6538
- stacks[key][x].setTotal(y);
6538
+
6539
+ // Read stacked values into a stack based on the x value,
6540
+ // the sign of y and the stack key. Stacking is also handled for null values (#739)
6541
+ if (stacking) {
6542
+ isNegative = y < threshold;
6543
+ pointStack = isNegative ? negPointStack : posPointStack;
6544
+ key = isNegative ? negKey : stackKey;
6545
+
6546
+ y = pointStack[x] =
6547
+ defined(pointStack[x]) ?
6548
+ correctFloat(pointStack[x] + y) :
6549
+ y;
6550
+
6551
+
6552
+ // add the series
6553
+ if (!stacks[key]) {
6554
+ stacks[key] = {};
6555
+ }
6539
6556
 
6557
+ // If the StackItem is there, just update the values,
6558
+ // if not, create one first
6559
+ if (!stacks[key][x]) {
6560
+ stacks[key][x] = new StackItem(axis, axis.options.stackLabels, isNegative, x, stackOption, stacking);
6561
+ }
6562
+ stacks[key][x].setTotal(y);
6563
+ }
6564
+
6565
+ // Handle non null values
6566
+ if (y !== null && y !== UNDEFINED) {
6540
6567
 
6541
6568
  // general hook, used for Highstock compare values feature
6542
- } else if (hasModifyValue) {
6569
+ if (hasModifyValue) {
6543
6570
  y = series.modifyValue(y);
6544
6571
  }
6545
6572
 
6546
- // get the smallest distance between points
6547
- /*if (i) {
6548
- distance = mathAbs(xData[i] - xData[i - 1]);
6549
- pointRange = pointRange === UNDEFINED ? distance : mathMin(distance, pointRange);
6550
- }*/
6551
-
6552
6573
  // for points within the visible range, including the first point outside the
6553
6574
  // visible range, consider y extremes
6554
6575
  if (cropped || ((xData[i + 1] || x) >= xExtremes.min && (xData[i - 1] || x) <= xExtremes.max)) {
@@ -6962,12 +6983,15 @@ Axis.prototype = {
6962
6983
  closestPointRange,
6963
6984
  minPointOffset = 0,
6964
6985
  pointRangePadding = 0,
6986
+ linkedParent = axis.linkedParent,
6965
6987
  transA = axis.transA;
6966
6988
 
6967
6989
  // adjust translation for padding
6968
6990
  if (axis.isXAxis) {
6969
- if (axis.isLinked) {
6970
- minPointOffset = axis.linkedParent.minPointOffset;
6991
+ if (linkedParent) {
6992
+ minPointOffset = linkedParent.minPointOffset;
6993
+ pointRangePadding = linkedParent.pointRangePadding;
6994
+
6971
6995
  } else {
6972
6996
  each(axis.series, function (series) {
6973
6997
  var seriesPointRange = series.pointRange,
@@ -7000,8 +7024,9 @@ Axis.prototype = {
7000
7024
  });
7001
7025
  }
7002
7026
 
7003
- // Record minPointOffse
7027
+ // Record minPointOffset and pointRangePadding
7004
7028
  axis.minPointOffset = minPointOffset;
7029
+ axis.pointRangePadding = pointRangePadding;
7005
7030
 
7006
7031
  // pointRange means the width reserved for each point, like in a column chart
7007
7032
  axis.pointRange = pointRange;
@@ -7941,9 +7966,6 @@ function Tooltip(chart, options) {
7941
7966
  // Current values of x and y when animating
7942
7967
  this.now = { x: 0, y: 0 };
7943
7968
 
7944
- // The tooltipTick function, initialized to nothing
7945
- //this.tooltipTick = UNDEFINED;
7946
-
7947
7969
  // The tooltip is initially hidden
7948
7970
  this.isHidden = true;
7949
7971
 
@@ -8011,13 +8033,21 @@ Tooltip.prototype = {
8011
8033
  // move to the intermediate value
8012
8034
  tooltip.label.attr(now);
8013
8035
 
8036
+
8014
8037
  // run on next tick of the mouse tracker
8015
8038
  if (animate && (mathAbs(x - now.x) > 1 || mathAbs(y - now.y) > 1)) {
8016
- tooltip.tooltipTick = function () {
8017
- tooltip.move(x, y, anchorX, anchorY);
8018
- };
8019
- } else {
8020
- tooltip.tooltipTick = null;
8039
+
8040
+ // never allow two timeouts
8041
+ clearTimeout(this.tooltipTimeout);
8042
+
8043
+ // set the fixed interval ticking for the smooth tooltip
8044
+ this.tooltipTimeout = setTimeout(function () {
8045
+ // The interval function may still be running during destroy, so check that the chart is really there before calling.
8046
+ if (tooltip) {
8047
+ tooltip.move(x, y, anchorX, anchorY);
8048
+ }
8049
+ }, 32);
8050
+
8021
8051
  }
8022
8052
  },
8023
8053
 
@@ -8114,7 +8144,7 @@ Tooltip.prototype = {
8114
8144
 
8115
8145
  // It is too far to the left, adjust it
8116
8146
  if (x < 7) {
8117
- x = plotLeft + pointX + distance;
8147
+ x = plotLeft + mathMax(pointX, 0) + distance;
8118
8148
  }
8119
8149
 
8120
8150
  // Test to see if the tooltip is too far to the right,
@@ -8140,7 +8170,6 @@ Tooltip.prototype = {
8140
8170
  if (y + boxHeight > plotTop + plotHeight) {
8141
8171
  y = mathMax(plotTop, plotTop + plotHeight - boxHeight - distance); // below
8142
8172
  }
8143
-
8144
8173
 
8145
8174
  return {x: x, y: y};
8146
8175
  },
@@ -8320,15 +8349,6 @@ Tooltip.prototype = {
8320
8349
  y: y + chart.plotTop,
8321
8350
  borderColor: borderColor
8322
8351
  });
8323
- },
8324
-
8325
- /**
8326
- * Runs the tooltip animation one tick.
8327
- */
8328
- tick: function () {
8329
- if (this.tooltipTick) {
8330
- this.tooltipTick();
8331
- }
8332
8352
  }
8333
8353
  };
8334
8354
  /**
@@ -8350,7 +8370,7 @@ function MouseTracker(chart, options) {
8350
8370
  this.chart = chart;
8351
8371
 
8352
8372
  // The interval id
8353
- //this.tooltipInterval = UNDEFINED;
8373
+ //this.tooltipTimeout = UNDEFINED;
8354
8374
 
8355
8375
  // The cached x hover position
8356
8376
  //this.hoverX = UNDEFINED;
@@ -8907,7 +8927,7 @@ MouseTracker.prototype = {
8907
8927
  container.onclick = container.onmousedown = container.onmousemove = container.ontouchstart = container.ontouchend = container.ontouchmove = null;
8908
8928
 
8909
8929
  // memory and CPU leak
8910
- clearInterval(this.tooltipInterval);
8930
+ clearInterval(this.tooltipTimeout);
8911
8931
  },
8912
8932
 
8913
8933
  // Run MouseTracker
@@ -8920,14 +8940,6 @@ MouseTracker.prototype = {
8920
8940
 
8921
8941
  if (options.enabled) {
8922
8942
  chart.tooltip = new Tooltip(chart, options);
8923
-
8924
- // set the fixed interval ticking for the smooth tooltip
8925
- this.tooltipInterval = setInterval(function () {
8926
- // The interval function may still be running during destroy, so check that the chart is really there before calling.
8927
- if (chart && chart.tooltip) {
8928
- chart.tooltip.tick();
8929
- }
8930
- }, 32);
8931
8943
  }
8932
8944
 
8933
8945
  this.setDOMEvents();
@@ -9012,19 +9024,37 @@ Legend.prototype = {
9012
9024
  legendSymbol = item.legendSymbol,
9013
9025
  hiddenColor = legend.itemHiddenStyle.color,
9014
9026
  textColor = visible ? options.itemStyle.color : hiddenColor,
9015
- symbolColor = visible ? item.color : hiddenColor;
9027
+ symbolColor = visible ? item.color : hiddenColor,
9028
+ markerOptions = item.options && item.options.marker,
9029
+ symbolAttr = {
9030
+ stroke: symbolColor,
9031
+ fill: symbolColor
9032
+ },
9033
+ key,
9034
+ val;
9016
9035
 
9036
+
9017
9037
  if (legendItem) {
9018
9038
  legendItem.css({ fill: textColor });
9019
9039
  }
9020
9040
  if (legendLine) {
9021
9041
  legendLine.attr({ stroke: symbolColor });
9022
9042
  }
9043
+
9023
9044
  if (legendSymbol) {
9024
- legendSymbol.attr({
9025
- stroke: symbolColor,
9026
- fill: symbolColor
9027
- });
9045
+
9046
+ // Apply marker options
9047
+ if (markerOptions) {
9048
+ markerOptions = item.convertAttribs(markerOptions);
9049
+ for (key in markerOptions) {
9050
+ val = markerOptions[key];
9051
+ if (val !== UNDEFINED) {
9052
+ symbolAttr[key] = val;
9053
+ }
9054
+ }
9055
+ }
9056
+
9057
+ legendSymbol.attr(symbolAttr);
9028
9058
  }
9029
9059
  },
9030
9060
 
@@ -9714,7 +9744,8 @@ Chart.prototype = {
9714
9744
  i = seriesLength,
9715
9745
  serie,
9716
9746
  renderer = chart.renderer,
9717
- isHiddenChart = renderer.isHidden();
9747
+ isHiddenChart = renderer.isHidden(),
9748
+ afterRedraw = [];
9718
9749
 
9719
9750
  setAnimation(animation, chart);
9720
9751
 
@@ -9778,7 +9809,9 @@ Chart.prototype = {
9778
9809
  // Fire 'afterSetExtremes' only if extremes are set
9779
9810
  if (axis.isDirtyExtremes) { // #821
9780
9811
  axis.isDirtyExtremes = false;
9781
- fireEvent(axis, 'afterSetExtremes', axis.getExtremes()); // #747, #751
9812
+ afterRedraw.push(function () { // prevent a recursive call to chart.redraw() (#1119)
9813
+ fireEvent(axis, 'afterSetExtremes', axis.getExtremes()); // #747, #751
9814
+ });
9782
9815
  }
9783
9816
 
9784
9817
  if (axis.isDirty || isDirtyBox || hasStackedSeries) {
@@ -9819,6 +9852,11 @@ Chart.prototype = {
9819
9852
  if (isHiddenChart) {
9820
9853
  chart.cloneRenderTo(true);
9821
9854
  }
9855
+
9856
+ // Fire callbacks that are put on hold until after the redraw
9857
+ each(afterRedraw, function (callback) {
9858
+ callback.call();
9859
+ });
9822
9860
  },
9823
9861
 
9824
9862
 
@@ -10379,9 +10417,9 @@ Chart.prototype = {
10379
10417
  initReflow: function () {
10380
10418
  var chart = this,
10381
10419
  optionsChart = chart.options.chart,
10382
- renderTo = chart.renderTo;
10383
-
10384
- var reflowTimeout;
10420
+ renderTo = chart.renderTo,
10421
+ reflowTimeout;
10422
+
10385
10423
  function reflow(e) {
10386
10424
  var width = optionsChart.width || adapterRun(renderTo, 'width'),
10387
10425
  height = optionsChart.height || adapterRun(renderTo, 'height'),
@@ -10393,8 +10431,10 @@ Chart.prototype = {
10393
10431
 
10394
10432
  if (width !== chart.containerWidth || height !== chart.containerHeight) {
10395
10433
  clearTimeout(reflowTimeout);
10396
- reflowTimeout = setTimeout(function () {
10397
- chart.resize(width, height, false);
10434
+ chart.reflowTimeout = reflowTimeout = setTimeout(function () {
10435
+ if (chart.container) { // It may have been destroyed in the meantime (#1257)
10436
+ chart.resize(width, height, false);
10437
+ }
10398
10438
  }, 100);
10399
10439
  }
10400
10440
  chart.containerWidth = width;
@@ -10483,7 +10523,7 @@ Chart.prototype = {
10483
10523
  }
10484
10524
 
10485
10525
  // Move resize button (#1115)
10486
- if (resetZoomButton) {
10526
+ if (resetZoomButton && resetZoomButton.align) {
10487
10527
  resetZoomButton.align(null, null, chart[resetZoomButton.alignTo]);
10488
10528
  }
10489
10529
 
@@ -10841,18 +10881,10 @@ Chart.prototype = {
10841
10881
  var chart = this,
10842
10882
  axes = chart.axes,
10843
10883
  series = chart.series,
10844
- container = chart.container;
10845
-
10846
- var i,
10884
+ container = chart.container,
10885
+ i,
10847
10886
  parentNode = container && container.parentNode;
10848
10887
 
10849
- // If the chart is destroyed already, do nothing.
10850
- // This will happen if if a script invokes chart.destroy and
10851
- // then it will be called again on win.unload
10852
- if (chart === null) {
10853
- return;
10854
- }
10855
-
10856
10888
  // fire the chart.destoy event
10857
10889
  fireEvent(chart, 'destroy');
10858
10890
 
@@ -10876,7 +10908,7 @@ Chart.prototype = {
10876
10908
  each(['title', 'subtitle', 'chartBackground', 'plotBackground', 'plotBGImage', 'plotBorder', 'seriesGroup', 'clipRect', 'credits', 'tracker', 'scroller', 'rangeSelector', 'legend', 'resetZoomButton', 'tooltip', 'renderer'], function (name) {
10877
10909
  var prop = chart[name];
10878
10910
 
10879
- if (prop) {
10911
+ if (prop && prop.destroy) {
10880
10912
  chart[name] = prop.destroy();
10881
10913
  }
10882
10914
  });
@@ -10889,8 +10921,6 @@ Chart.prototype = {
10889
10921
  discardElement(container);
10890
10922
  }
10891
10923
 
10892
- // IE6 leak
10893
- container = null;
10894
10924
  }
10895
10925
 
10896
10926
  // clean it all up
@@ -10898,8 +10928,6 @@ Chart.prototype = {
10898
10928
  delete chart[i];
10899
10929
  }
10900
10930
 
10901
- chart.options = null;
10902
- chart = null;
10903
10931
  },
10904
10932
 
10905
10933
  /**
@@ -11297,7 +11325,7 @@ Point.prototype = {
11297
11325
  parts,
11298
11326
  prop,
11299
11327
  i,
11300
- cfg = { // docs: percentageDecimals, percentagePrefix, percentageSuffix, totalDecimals, totalPrefix, totalSuffix
11328
+ cfg = {
11301
11329
  y: 0, // 0: use 'value' for repOptionKey
11302
11330
  open: 0,
11303
11331
  high: 0,
@@ -11875,7 +11903,6 @@ Series.prototype = {
11875
11903
  2 * radius,
11876
11904
  2 * radius
11877
11905
  )
11878
- .attr(this.pointAttr[NORMAL_STATE])
11879
11906
  .add(legendItemGroup);
11880
11907
  }
11881
11908
  },
@@ -12298,7 +12325,11 @@ Series.prototype = {
12298
12325
  yValue = yBottom + yValue;
12299
12326
 
12300
12327
  if (isBottomSeries) {
12301
- yBottom = pick(options.threshold, yAxis.isLog ? null : yAxis.min); // #1200
12328
+ yBottom = pick(options.threshold, yAxis.min);
12329
+ }
12330
+
12331
+ if (yAxis.isLog && yBottom <= 0) { // #1200, #1232
12332
+ yBottom = null;
12302
12333
  }
12303
12334
 
12304
12335
  if (stacking === 'percent') {
@@ -12417,7 +12448,7 @@ Series.prototype = {
12417
12448
  }
12418
12449
 
12419
12450
  return tooltipOptions.headerFormat
12420
- .replace('{point.key}', isDateTime ? dateFormat(xDateFormat, key) : key)
12451
+ .replace('{point.key}', isDateTime && isNumber(key) ? dateFormat(xDateFormat, key) : key)
12421
12452
  .replace('{series.name}', series.name)
12422
12453
  .replace('{series.color}', series.color);
12423
12454
  },
@@ -12636,6 +12667,9 @@ Series.prototype = {
12636
12667
  .attr(pointAttr)
12637
12668
  .add(markerGroup);
12638
12669
  }
12670
+
12671
+ } else if (graphic) {
12672
+ point.graphic = graphic.destroy(); // #1269
12639
12673
  }
12640
12674
  }
12641
12675
  }
@@ -12875,59 +12909,21 @@ Series.prototype = {
12875
12909
 
12876
12910
  var series = this,
12877
12911
  seriesOptions = series.options,
12878
- options = seriesOptions.dataLabels;
12912
+ options = seriesOptions.dataLabels,
12913
+ points = series.points,
12914
+ pointOptions,
12915
+ generalOptions,
12916
+ str,
12917
+ dataLabelsGroup;
12879
12918
 
12880
12919
  if (options.enabled || series._hasPointLabels) {
12881
- var x,
12882
- y,
12883
- points = series.points,
12884
- pointOptions,
12885
- generalOptions,
12886
- str,
12887
- dataLabelsGroup,
12888
- chart = series.chart,
12889
- renderer = chart.renderer,
12890
- inverted = chart.inverted,
12891
- seriesType = series.type,
12892
- stacking = seriesOptions.stacking,
12893
- isBarLike = seriesType === 'column' || seriesType === 'bar',
12894
- vAlignIsNull = options.verticalAlign === null,
12895
- yIsNull = options.y === null,
12896
- fontMetrics = renderer.fontMetrics(options.style.fontSize), // height and baseline
12897
- fontLineHeight = fontMetrics.h,
12898
- fontBaseline = fontMetrics.b;
12899
-
12900
- if (isBarLike) {
12901
- var defaultYs = {
12902
- top: fontBaseline,
12903
- middle: fontBaseline - fontLineHeight / 2,
12904
- bottom: -fontLineHeight + fontBaseline
12905
- };
12906
- if (stacking) {
12907
- // In stacked series the default label placement is inside the bars
12908
- if (vAlignIsNull) {
12909
- options = merge(options, {verticalAlign: 'middle'});
12910
- }
12911
-
12912
- // If no y delta is specified, try to create a good default
12913
- if (yIsNull) {
12914
- options = merge(options, { y: defaultYs[options.verticalAlign]});
12915
- }
12916
- } else {
12917
- // In non stacked series the default label placement is on top of the bars
12918
- if (vAlignIsNull) {
12919
- options = merge(options, {verticalAlign: 'top'});
12920
-
12921
- // If no y delta is specified, try to create a good default (like default bar)
12922
- } else if (yIsNull) {
12923
- options = merge(options, { y: defaultYs[options.verticalAlign]});
12924
- }
12925
-
12926
- }
12920
+
12921
+ // Process default alignment of data labels for columns
12922
+ if (series.dlProcessOptions) {
12923
+ series.dlProcessOptions(options);
12927
12924
  }
12928
12925
 
12929
-
12930
- // create a separate group for the data labels to avoid rotation
12926
+ // Create a separate group for the data labels to avoid rotation
12931
12927
  dataLabelsGroup = series.plotGroup(
12932
12928
  'dataLabelsGroup',
12933
12929
  'data-labels',
@@ -12935,47 +12931,21 @@ Series.prototype = {
12935
12931
  6
12936
12932
  );
12937
12933
 
12938
- // make the labels for each point
12934
+ // Make the labels for each point
12939
12935
  generalOptions = options;
12940
12936
  each(points, function (point) {
12941
12937
 
12942
- var plotX,
12943
- plotY,
12944
- individualYDelta,
12945
- enabled,
12946
- dataLabel = point.dataLabel;
12947
-
12948
- // Merge in individual options from point
12949
- options = generalOptions; // reset changes from previous points
12950
- pointOptions = point.options;
12951
- if (pointOptions && pointOptions.dataLabels) {
12952
- options = merge(options, pointOptions.dataLabels);
12953
- }
12954
- enabled = options.enabled;
12938
+ var enabled,
12939
+ dataLabel = point.dataLabel,
12940
+ attr,
12941
+ name,
12942
+ rotation,
12943
+ isNew = true;
12955
12944
 
12956
- // Get the positions
12957
- if (enabled) {
12958
- plotX = (point.barX && point.barX + point.barW / 2) || pick(point.plotX, -999);
12959
- plotY = pick(point.plotY, -999);
12960
-
12961
- // if options.y is null, which happens by default on column charts, set the position
12962
- // above or below the column depending on the threshold
12963
- individualYDelta = options.y === null ?
12964
- (point.y >= seriesOptions.threshold ?
12965
- -fontLineHeight + fontBaseline : // below the threshold
12966
- fontBaseline) : // above the threshold
12967
- options.y;
12968
-
12969
- x = (inverted ? chart.plotWidth - plotY : plotX) + options.x;
12970
- y = mathRound((inverted ? chart.plotHeight - plotX : plotY) + individualYDelta);
12971
-
12972
- }
12945
+ // Determine if each data label is enabled
12946
+ pointOptions = point.options && point.options.dataLabels;
12947
+ enabled = generalOptions.enabled || (pointOptions && pointOptions.enabled);
12973
12948
 
12974
- // Check if the individual label must be disabled due to either falling
12975
- // ouside the plot area, or the enabled option being switched off
12976
- if (series.isCartesian && !chart.isInsidePlot(x - options.x, y)) {
12977
- enabled = false;
12978
- }
12979
12949
 
12980
12950
  // If the point is outside the plot area, destroy it. #678, #820
12981
12951
  if (dataLabel && !enabled) {
@@ -12985,23 +12955,15 @@ Series.prototype = {
12985
12955
  // in the point options, or if they fall outside the plot area.
12986
12956
  } else if (enabled) {
12987
12957
 
12988
- var align = options.align,
12989
- attr,
12990
- name;
12958
+ rotation = options.rotation;
12959
+
12960
+ // Create individual options structure that can be extended without
12961
+ // affecting others
12962
+ options = merge(generalOptions, pointOptions);
12991
12963
 
12992
12964
  // Get the string
12993
12965
  str = options.formatter.call(point.getLabelConfig(), options);
12994
12966
 
12995
- // in columns, align the string to the column
12996
- if (seriesType === 'column') {
12997
- x += { left: -1, right: 1 }[align] * point.barW / 2 || 0;
12998
- }
12999
-
13000
- if (!stacking && inverted && point.y < 0) {
13001
- align = 'right';
13002
- x -= 10;
13003
- }
13004
-
13005
12967
  // Determine the color
13006
12968
  options.style.color = pick(options.color, options.style.color, series.color, 'black');
13007
12969
 
@@ -13012,19 +12974,17 @@ Series.prototype = {
13012
12974
  dataLabel
13013
12975
  .attr({
13014
12976
  text: str
13015
- }).animate({
13016
- x: x,
13017
- y: y
13018
12977
  });
12978
+ isNew = false;
13019
12979
  // create new label
13020
12980
  } else if (defined(str)) {
13021
12981
  attr = {
13022
- align: align,
12982
+ //align: align,
13023
12983
  fill: options.backgroundColor,
13024
12984
  stroke: options.borderColor,
13025
12985
  'stroke-width': options.borderWidth,
13026
12986
  r: options.borderRadius || 0,
13027
- rotation: options.rotation,
12987
+ rotation: rotation,
13028
12988
  padding: options.padding,
13029
12989
  zIndex: 1
13030
12990
  };
@@ -13035,43 +12995,78 @@ Series.prototype = {
13035
12995
  }
13036
12996
  }
13037
12997
 
13038
- dataLabel = point.dataLabel = renderer[options.rotation ? 'text' : 'label']( // labels don't support rotation
12998
+ dataLabel = point.dataLabel = series.chart.renderer[rotation ? 'text' : 'label']( // labels don't support rotation
13039
12999
  str,
13040
- x,
13041
- y,
13000
+ 0,
13001
+ -999,
13042
13002
  null,
13043
13003
  null,
13044
13004
  null,
13045
- options.useHTML,
13046
- true // baseline for backwards compat
13005
+ options.useHTML
13047
13006
  )
13048
13007
  .attr(attr)
13049
13008
  .css(options.style)
13050
13009
  .add(dataLabelsGroup)
13051
13010
  .shadow(options.shadow);
13011
+
13052
13012
  }
13053
-
13054
- if (isBarLike && seriesOptions.stacking && dataLabel) {
13055
- var barX = point.barX,
13056
- barY = point.barY,
13057
- barW = point.barW,
13058
- barH = point.barH;
13059
-
13060
- dataLabel.align(options, null,
13061
- {
13062
- x: inverted ? chart.plotWidth - barY - barH : barX,
13063
- y: inverted ? chart.plotHeight - barX - barW : barY,
13064
- width: inverted ? barH : barW,
13065
- height: inverted ? barW : barH
13066
- });
13067
- }
13068
-
13069
13013
 
13014
+ // Now the data label is created and placed at 0,0, so we need to align it
13015
+ if (dataLabel) {
13016
+ series.alignDataLabel(point, dataLabel, options, null, isNew);
13017
+ }
13070
13018
  }
13071
13019
  });
13072
13020
  }
13073
13021
  },
13074
13022
 
13023
+ /**
13024
+ * Align each individual data label
13025
+ */
13026
+ alignDataLabel: function (point, dataLabel, options, alignTo, isNew) {
13027
+ var chart = this.chart,
13028
+ inverted = chart.inverted,
13029
+ plotX = pick(point.plotX, -999),
13030
+ plotY = pick(point.plotY, -999),
13031
+ bBox = dataLabel.getBBox(),
13032
+ alignAttr; // the final position;
13033
+
13034
+ // The alignment box is a singular point
13035
+ alignTo = extend({
13036
+ x: inverted ? chart.plotWidth - plotY : plotX,
13037
+ y: mathRound(inverted ? chart.plotHeight - plotX : plotY),
13038
+ width: 0,
13039
+ height: 0
13040
+ }, alignTo);
13041
+
13042
+ // Add the text size for alignment calculation
13043
+ extend(options, {
13044
+ width: bBox.width,
13045
+ height: bBox.height
13046
+ });
13047
+
13048
+ // Allow a hook for changing alignment in the last moment, then do the alignment
13049
+ if (options.rotation) { // Fancy box alignment isn't supported for rotated text
13050
+ alignAttr = {
13051
+ align: options.align,
13052
+ x: alignTo.x + options.x + alignTo.width / 2,
13053
+ y: alignTo.y + options.y + alignTo.height / 2
13054
+ };
13055
+ dataLabel[isNew ? 'attr' : 'animate'](alignAttr);
13056
+ } else {
13057
+ dataLabel.align(options, null, alignTo);
13058
+ alignAttr = dataLabel.alignAttr;
13059
+ }
13060
+
13061
+ // Show or hide based on the final aligned position
13062
+ dataLabel.attr({
13063
+ visibility: options.crop === false || chart.isInsidePlot(alignAttr.x, alignAttr.y) || chart.isInsidePlot(plotX, plotY, inverted) ?
13064
+ (hasSVG ? 'inherit' : VISIBLE) :
13065
+ HIDDEN
13066
+ });
13067
+
13068
+ },
13069
+
13075
13070
  /**
13076
13071
  * Return the graph path of a segment
13077
13072
  */
@@ -13270,8 +13265,6 @@ Series.prototype = {
13270
13265
  chartSeriesGroup
13271
13266
  );
13272
13267
 
13273
- series.drawDataLabels();
13274
-
13275
13268
  // initiate the animation
13276
13269
  if (doAnimation) {
13277
13270
  series.animate(true);
@@ -13290,6 +13283,10 @@ Series.prototype = {
13290
13283
 
13291
13284
  // draw the points
13292
13285
  series.drawPoints();
13286
+
13287
+ // draw the data labels
13288
+ series.drawDataLabels();
13289
+
13293
13290
 
13294
13291
  // draw the mouse tracking area
13295
13292
  if (series.options.enableMouseTracking !== false) {
@@ -13880,8 +13877,9 @@ defaultPlotOptions.column = merge(defaultSeriesOptions, {
13880
13877
  }
13881
13878
  },
13882
13879
  dataLabels: {
13883
- y: null,
13884
- verticalAlign: null
13880
+ align: null, // auto
13881
+ verticalAlign: null, // auto
13882
+ y: null
13885
13883
  },
13886
13884
  threshold: 0
13887
13885
  });
@@ -13981,7 +13979,7 @@ var ColumnSeries = extendClass(Series, {
13981
13979
  pointOffsetWidth - (categoryWidth / 2)) *
13982
13980
  (reversedXAxis ? -1 : 1),
13983
13981
  threshold = options.threshold,
13984
- translatedThreshold = series.yAxis.getThreshold(threshold),
13982
+ translatedThreshold = series.translatedThreshold = series.yAxis.getThreshold(threshold),
13985
13983
  minPointLength = pick(options.minPointLength, 5);
13986
13984
 
13987
13985
  // record the new values
@@ -14010,13 +14008,8 @@ var ColumnSeries = extendClass(Series, {
14010
14008
  }
14011
14009
  }
14012
14010
 
14013
- extend(point, {
14014
- barX: barX,
14015
- barY: barY,
14016
- barW: barW,
14017
- barH: barH,
14018
- pointWidth: pointWidth
14019
- });
14011
+ point.barX = barX;
14012
+ point.pointWidth = pointWidth;
14020
14013
 
14021
14014
  // create shape type and shape args that are reused in drawPoints and drawTracker
14022
14015
  point.shapeType = 'rect';
@@ -14058,15 +14051,14 @@ var ColumnSeries = extendClass(Series, {
14058
14051
  var series = this,
14059
14052
  options = series.options,
14060
14053
  renderer = series.chart.renderer,
14061
- graphic,
14062
14054
  shapeArgs;
14063
14055
 
14064
14056
 
14065
14057
  // draw the columns
14066
14058
  each(series.points, function (point) {
14067
- var plotY = point.plotY;
14068
- if (plotY !== UNDEFINED && !isNaN(plotY) && point.y !== null) {
14059
+ var plotY = point.plotY,
14069
14060
  graphic = point.graphic;
14061
+ if (plotY !== UNDEFINED && !isNaN(plotY) && point.y !== null) {
14070
14062
  shapeArgs = point.shapeArgs;
14071
14063
  if (graphic) { // update
14072
14064
  stop(graphic);
@@ -14079,6 +14071,8 @@ var ColumnSeries = extendClass(Series, {
14079
14071
  .shadow(options.shadow, null, options.stacking && !options.borderRadius);
14080
14072
  }
14081
14073
 
14074
+ } else if (graphic) {
14075
+ point.graphic = graphic.destroy(); // #1269
14082
14076
  }
14083
14077
  });
14084
14078
  },
@@ -14141,6 +14135,54 @@ var ColumnSeries = extendClass(Series, {
14141
14135
  }
14142
14136
  });
14143
14137
  },
14138
+
14139
+ /**
14140
+ * Override the basic data label alignment by adjusting for the position of the column
14141
+ */
14142
+ alignDataLabel: function (point, dataLabel, options, alignTo, isNew) {
14143
+ var chart = this.chart,
14144
+ inverted = chart.inverted,
14145
+ below = point.below || (point.plotY > (this.translatedThreshold || chart.plotSizeY)),
14146
+ inside = (this.options.stacking || options.inside); // draw it inside the box?
14147
+
14148
+ // Align to the column itself, or the top of it
14149
+ if (point.shapeArgs) { // Area range uses this method but not alignTo
14150
+ alignTo = merge(point.shapeArgs);
14151
+ if (inverted) {
14152
+ alignTo = {
14153
+ x: chart.plotWidth - alignTo.y - alignTo.height,
14154
+ y: chart.plotHeight - alignTo.x - alignTo.width,
14155
+ width: alignTo.height,
14156
+ height: alignTo.width
14157
+ };
14158
+ }
14159
+
14160
+ // Compute the alignment box
14161
+ if (!inside) {
14162
+ if (inverted) {
14163
+ alignTo.x += below ? 0 : alignTo.width;
14164
+ alignTo.width = 0;
14165
+ } else {
14166
+ alignTo.y += below ? alignTo.height : 0;
14167
+ alignTo.height = 0;
14168
+ }
14169
+ }
14170
+ }
14171
+
14172
+ // When alignment is undefined (typically columns and bars), display the individual
14173
+ // point below or above the point depending on the threshold
14174
+ options.align = pick(
14175
+ options.align,
14176
+ !inverted || inside ? 'center' : below ? 'right' : 'left'
14177
+ );
14178
+ options.verticalAlign = pick(
14179
+ options.verticalAlign,
14180
+ inverted || inside ? 'middle' : below ? 'top' : 'bottom'
14181
+ );
14182
+
14183
+ // Call the parent method
14184
+ Series.prototype.alignDataLabel.call(this, point, dataLabel, options, alignTo, isNew);
14185
+ },
14144
14186
 
14145
14187
 
14146
14188
  /**
@@ -14214,14 +14256,7 @@ seriesTypes.column = ColumnSeries;
14214
14256
  /**
14215
14257
  * Set the default options for bar
14216
14258
  */
14217
- defaultPlotOptions.bar = merge(defaultPlotOptions.column, {
14218
- dataLabels: {
14219
- align: 'left',
14220
- x: 5,
14221
- y: null,
14222
- verticalAlign: 'middle'
14223
- }
14224
- });
14259
+ defaultPlotOptions.bar = merge(defaultPlotOptions.column);
14225
14260
  /**
14226
14261
  * The Bar series class
14227
14262
  */
@@ -14334,9 +14369,9 @@ defaultPlotOptions.pie = merge(defaultSeriesOptions, {
14334
14369
  enabled: true,
14335
14370
  formatter: function () {
14336
14371
  return this.point.name;
14337
- },
14372
+ }
14338
14373
  // softConnector: true,
14339
- y: 5
14374
+ //y: 0
14340
14375
  },
14341
14376
  //innerSize: 0,
14342
14377
  legendType: 'point',
@@ -14578,7 +14613,10 @@ var PieSeries = {
14578
14613
  radiusX, // the x component of the radius vector for a given point
14579
14614
  radiusY,
14580
14615
  labelDistance = options.dataLabels.distance,
14581
- ignoreHiddenPoint = options.ignoreHiddenPoint;
14616
+ ignoreHiddenPoint = options.ignoreHiddenPoint,
14617
+ i,
14618
+ len = points.length,
14619
+ point;
14582
14620
 
14583
14621
  // get positions - either an integer or a percentage string must be given
14584
14622
  series.center = positions = series.getCenter();
@@ -14594,11 +14632,16 @@ var PieSeries = {
14594
14632
  };
14595
14633
 
14596
14634
  // get the total sum
14597
- each(points, function (point) {
14635
+ for (i = 0; i < len; i++) {
14636
+ point = points[i];
14598
14637
  total += (ignoreHiddenPoint && !point.visible) ? 0 : point.y;
14599
- });
14638
+ }
14600
14639
 
14601
- each(points, function (point) {
14640
+ // Calculate the geometry for each point
14641
+ for (i = 0; i < len; i++) {
14642
+
14643
+ point = points[i];
14644
+
14602
14645
  // set start and end angle
14603
14646
  fraction = total ? point.y / total : 0;
14604
14647
  start = mathRound(cumulative * circ * precision) / precision;
@@ -14651,7 +14694,7 @@ var PieSeries = {
14651
14694
  point.percentage = fraction * 100;
14652
14695
  point.total = total;
14653
14696
 
14654
- });
14697
+ }
14655
14698
 
14656
14699
 
14657
14700
  this.setTooltipPoints();
@@ -14952,7 +14995,7 @@ var PieSeries = {
14952
14995
  })[dataLabel.moved ? 'animate' : 'attr']({
14953
14996
  x: x + options.x +
14954
14997
  ({ left: connectorPadding, right: -connectorPadding }[labelPos[6]] || 0),
14955
- y: y + options.y
14998
+ y: y + options.y - 10 // 10 is for the baseline (label vs text)
14956
14999
  });
14957
15000
  dataLabel.moved = true;
14958
15001
 
@@ -14996,6 +15039,8 @@ var PieSeries = {
14996
15039
  }
14997
15040
  }
14998
15041
  },
15042
+
15043
+ alignDataLabel: noop,
14999
15044
 
15000
15045
  /**
15001
15046
  * Draw point specific tracker objects. Inherit directly from column series.
@@ -15061,6 +15106,6 @@ extend(Highcharts, {
15061
15106
  canvas: useCanVG,
15062
15107
  vml: !hasSVG && !useCanVG,
15063
15108
  product: 'Highcharts',
15064
- version: '2.3.2'
15109
+ version: '2.3.3'
15065
15110
  });
15066
15111
  }());