highcharts-js-rails 0.1.10 → 0.1.11

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,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
  }());