highcharts-rails 4.1.8 → 4.1.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b5d2613cbe4c6a3f1071f83ec6fe79c4f94e6d51
4
- data.tar.gz: a505f22fce9e0075c5012d3f5a73dced8940673d
3
+ metadata.gz: 1827827713b7d5903723ab0d6262529fb803740e
4
+ data.tar.gz: 1332236b9132993e7f71b862c337d14b06b10be3
5
5
  SHA512:
6
- metadata.gz: 9009c0a9b5bb8bcd42150a35838f3b45ea00917509ae8150b6054004be300301fd3512e3e55b8450217d2b82b8f23290c01a98318ea0a85ab046bf6061cf7201
7
- data.tar.gz: bd615ab24486525622bb2e0d3038d49359ec7ddb4d2f478dea63f9fe6d6677672be96b0c5f7d7158a7f40e7982a8b35cade4ce80306e14e598bd5ddd875007cc
6
+ metadata.gz: b24a7286c9a863d82d90d43ff7af3308d41db6658206e51d13a2c152b184bb0aa0de9a759731304e1af22de5e211687ea54800647ed6e3c4b9b18d3a5bf25c48
7
+ data.tar.gz: 56210d460aac71f1b87c0da61edf2357e39e293c76d66711a17ee8e7377eb6425d1678a100e22fa50a1976fd9fa184ad417bf9b3ae1b7777574ef60821512148
@@ -1,3 +1,54 @@
1
+ # 4.1.9 / 2015-12-04
2
+
3
+ * Updated Highcharts to 4.1.9 (2015-10-07)
4
+ * Added new option, axis.visible.
5
+ * Added new option, bubble.sizeByAbsoluteValue, to allow negative bubbles sizes to be based on the absolute value rather than a scalar difference from smallest to greatest. Closes #4498.
6
+ * Added new series option, softThreshold, to prevent showing subzero axis ticks for line series that consist of positive data only.
7
+ * Added support for legendType: 'point' on more series types than just pie and its derivatives.
8
+ * Fixed #2473, allowHTML should not affect the forExport flag.
9
+ * Fixed #2711, set proper order of data labels inside columns.
10
+ * Fixed #2854, SVG images in symbol URL's did not display in IE11.
11
+ * Fixed #3529, selected point changed color after updating.
12
+ * Fixed #3542, tooltip with useHTML did not fade out smoothly.
13
+ * Fixed #3632, pie inner size shouldn't be allowed to be greater than outer size.
14
+ * Fixed #3636, negativeColor wasn't set for marker on hover.
15
+ * Fixed #3801, pie chart radial gradient position did not update on chart resize.
16
+ * Fixed #3971, X axis label step was not honoured when rotation was set.
17
+ * Fixed #4136, treemap did not export correctly after drillToNode.
18
+ * Fixed #4298, treemap did not update axis extremes after updated data.
19
+ * Fixed #4431, tooltip was broken when changing from column series to a different type.
20
+ * Fixed #4442, alignTicks forced axes to align, even when only one of them contained data.
21
+ * Fixed #4465, tooltip disappeared on point when stickyTracking was false.
22
+ * Fixed #4482, line disappeared during animation when series.step was enabled.
23
+ * Fixed #4485, ticks were added inside axis break on datetime axis.
24
+ * Fixed #4502, wrong bounding box detection of rotated labels caused overlapping text in old IE.
25
+ * Fixed #4504, bars were misplaced when using reversed yAxis.
26
+ * Fixed #4510, point search along X axis failed in boost module.
27
+ * Fixed #4511, tooltip was not displayed, when yAxis.max cut off top part of the column.
28
+ * Fixed #4519, updatating pie data immediately failed with Standalone Framework.
29
+ * Fixed #4525, errors in exported SVG when allowHTML was true.
30
+ * Fixed #4526, series used the same clip-paths, which caused wrong clipping when using different axes.
31
+ * Fixed #4529, boost module produced error with pie charts.
32
+ * Fixed #4530, heatmap with single point and large colsize caused the point not to display.
33
+ * Fixed #4532, stack ID's as strings caused JS error in Highcharts 3D.
34
+ * Fixed #4536, unable to zoom in closely on first category when minRange was less than closest point range.
35
+ * Fixed #4543, null value bubbles should not be drawn.
36
+ * Fixed #4546, pie and flag series not showing tooltip correctly when displayed in a chart with shared tooltip.
37
+ * Fixed #4558, when resizing chart during addPoint animation cause error in stacking.
38
+ * Fixed #4562, logarithmic zAxis for 3D scatter did not render properly points.
39
+ * Fixed #4586, some markers moved by 1px after hovering.
40
+ * Fixed #4594, errors when stacking two series with different data lengths on a log axis.
41
+ * Fixed #4599, cropThreshold should be ignored when getExtremesFromAll is enabled.
42
+ * Fixed #4615, labels on color axis were wrongly positioned when useHTML.
43
+ * Fixed #4627, data labels exported twice in IE and Edge. Text shadows not rendered in Edge.
44
+ * Fixed issue with duplicated pane backgrounds after the #3176 fix.
45
+ * Fixed issue with offline export in Firefox. Closes #4550.
46
+ * Fixed regression with global animation and timing of calls.
47
+ * Fixed #2801, whiskerLength for boxplot can be set in pixels.
48
+ * Fixed #3323, 3d pie parts have better zIndexes, out part of slice crossing sides created, normalization of alpha and beta to (-360, 360) range.
49
+ * Partly fixed #1686, tooltip not hiding when mouse enters over it then out from series.
50
+ * Refactored columns. Separated the crisping logic from the rest of the translation logic. Related to #4179.
51
+
1
52
  # 4.1.8 / 2015-08-31
2
53
 
3
54
  * Updated Highcharts to 4.1.8 (2015-08-20)
@@ -2,7 +2,7 @@
2
2
  // @compilation_level SIMPLE_OPTIMIZATIONS
3
3
 
4
4
  /**
5
- * @license Highcharts JS v4.1.8 (2015-08-20)
5
+ * @license Highcharts JS v4.1.9 (2015-10-07)
6
6
  *
7
7
  * (c) 2009-2014 Torstein Honsi
8
8
  *
@@ -33,15 +33,15 @@ var UNDEFINED,
33
33
  // some variables
34
34
  userAgent = navigator.userAgent,
35
35
  isOpera = win.opera,
36
- isIE = /(msie|trident)/i.test(userAgent) && !isOpera,
36
+ isMS = /(msie|trident|edge)/i.test(userAgent) && !isOpera,
37
37
  docMode8 = doc.documentMode === 8,
38
- isWebKit = /AppleWebKit/.test(userAgent),
38
+ isWebKit = !isMS && /AppleWebKit/.test(userAgent),
39
39
  isFirefox = /Firefox/.test(userAgent),
40
40
  isTouchDevice = /(Mobile|Android|Windows Phone)/.test(userAgent),
41
41
  SVG_NS = 'http://www.w3.org/2000/svg',
42
42
  hasSVG = !!doc.createElementNS && !!doc.createElementNS(SVG_NS, 'svg').createSVGRect,
43
43
  hasBidiBug = isFirefox && parseInt(userAgent.split('Firefox/')[1], 10) < 4, // issue #38
44
- useCanVG = !hasSVG && !isIE && !!doc.createElement('canvas').getContext,
44
+ useCanVG = !hasSVG && !isMS && !!doc.createElement('canvas').getContext,
45
45
  Renderer,
46
46
  hasTouch,
47
47
  symbolSizes = {},
@@ -55,7 +55,7 @@ var UNDEFINED,
55
55
  charts = [],
56
56
  chartCount = 0,
57
57
  PRODUCT = 'Highcharts',
58
- VERSION = '4.1.8',
58
+ VERSION = '4.1.9',
59
59
 
60
60
  // some constants for frequently used strings
61
61
  DIV = 'div',
@@ -312,7 +312,7 @@ var pick = Highcharts.pick = function () {
312
312
  * @param {Object} styles Style object with camel case property names
313
313
  */
314
314
  function css(el, styles) {
315
- if (isIE && !hasSVG) { // #2686
315
+ if (isMS && !hasSVG) { // #2686
316
316
  if (styles && styles.opacity !== UNDEFINED) {
317
317
  styles.filter = 'alpha(opacity=' + (styles.opacity * 100) + ')';
318
318
  }
@@ -1118,7 +1118,7 @@ pathAnim = {
1118
1118
  //
1119
1119
  // To avoid problems in IE (see #1010) where we cannot delete the properties and avoid
1120
1120
  // testing if they are there (warning in chrome) the only option is to test if running IE.
1121
- if (!isIE && eventArguments) {
1121
+ if (!isMS && eventArguments) {
1122
1122
  delete eventArguments.layerX;
1123
1123
  delete eventArguments.layerY;
1124
1124
  delete eventArguments.returnValue;
@@ -1269,8 +1269,8 @@ defaultOptions = {
1269
1269
  global: {
1270
1270
  useUTC: true,
1271
1271
  //timezoneOffset: 0,
1272
- canvasToolsURL: 'http://code.highcharts.com/4.1.8/modules/canvas-tools.js',
1273
- VMLRadialGradientURL: 'http://code.highcharts.com/4.1.8/gfx/vml-radial-gradient.png'
1272
+ canvasToolsURL: 'http://code.highcharts.com/4.1.9/modules/canvas-tools.js',
1273
+ VMLRadialGradientURL: 'http://code.highcharts.com/4.1.9/gfx/vml-radial-gradient.png'
1274
1274
  },
1275
1275
  chart: {
1276
1276
  //animation: true,
@@ -1413,6 +1413,7 @@ defaultOptions = {
1413
1413
  //pointStart: 0,
1414
1414
  //pointInterval: 1,
1415
1415
  //showInLegend: null, // auto: true for standalone series, false for linked series
1416
+ softThreshold: true,
1416
1417
  states: { // states for the entire series
1417
1418
  hover: {
1418
1419
  //enabled: false,
@@ -1554,6 +1555,7 @@ defaultOptions = {
1554
1555
  cursor: 'default',
1555
1556
  fontSize: '12px',
1556
1557
  padding: '8px',
1558
+ pointerEvents: 'none', // #1686 http://caniuse.com/#feat=pointer-events
1557
1559
  whiteSpace: 'nowrap'
1558
1560
  }
1559
1561
  //xDateFormat: '%A, %b %e, %Y',
@@ -1841,6 +1843,7 @@ SVGElement.prototype = {
1841
1843
  colorObject,
1842
1844
  gradName,
1843
1845
  gradAttr,
1846
+ radAttr,
1844
1847
  gradients,
1845
1848
  gradientObject,
1846
1849
  stops,
@@ -1877,12 +1880,11 @@ SVGElement.prototype = {
1877
1880
 
1878
1881
  // Correct the radial gradient for the radial reference system
1879
1882
  if (gradName === 'radialGradient' && radialReference && !defined(gradAttr.gradientUnits)) {
1880
- gradAttr = merge(gradAttr, {
1881
- cx: (radialReference[0] - radialReference[2] / 2) + gradAttr.cx * radialReference[2],
1882
- cy: (radialReference[1] - radialReference[2] / 2) + gradAttr.cy * radialReference[2],
1883
- r: gradAttr.r * radialReference[2],
1884
- gradientUnits: 'userSpaceOnUse'
1885
- });
1883
+ radAttr = gradAttr; // Save the radial attributes for updating
1884
+ gradAttr = merge(gradAttr,
1885
+ renderer.getRadialAttr(radialReference, radAttr),
1886
+ { gradientUnits: 'userSpaceOnUse' }
1887
+ );
1886
1888
  }
1887
1889
 
1888
1890
  // Build the unique key to detect whether we need to create a new element (#1282)
@@ -1908,6 +1910,7 @@ SVGElement.prototype = {
1908
1910
  .attr(gradAttr)
1909
1911
  .add(renderer.defs);
1910
1912
 
1913
+ gradientObject.radAttr = radAttr;
1911
1914
 
1912
1915
  // The gradient needs to keep a list of stops to be able to destroy them
1913
1916
  gradientObject.stops = [];
@@ -1934,6 +1937,7 @@ SVGElement.prototype = {
1934
1937
 
1935
1938
  // Set the reference to the gradient object
1936
1939
  elem.setAttribute(prop, 'url(' + renderer.url + '#' + id + ')');
1940
+ elem.gradient = key;
1937
1941
  }
1938
1942
  },
1939
1943
 
@@ -1950,9 +1954,10 @@ SVGElement.prototype = {
1950
1954
  tspans,
1951
1955
  hasContrast = textShadow.indexOf('contrast') !== -1,
1952
1956
  styles = {},
1957
+ forExport = this.renderer.forExport,
1953
1958
  // IE10 and IE11 report textShadow in elem.style even though it doesn't work. Check
1954
1959
  // this again with new IE release. In exports, the rendering is passed to PhantomJS.
1955
- supports = this.renderer.forExport || (elem.style.textShadow !== UNDEFINED && !isIE);
1960
+ supports = forExport || (elem.style.textShadow !== UNDEFINED && !isMS);
1956
1961
 
1957
1962
  // When the text shadow is set to contrast, use dark stroke for light text and vice versa
1958
1963
  if (hasContrast) {
@@ -1961,7 +1966,7 @@ SVGElement.prototype = {
1961
1966
 
1962
1967
  // Safari with retina displays as well as PhantomJS bug (#3974). Firefox does not tolerate this,
1963
1968
  // it removes the text shadows.
1964
- if (isWebKit) {
1969
+ if (isWebKit || forExport) {
1965
1970
  styles.textRendering = 'geometricPrecision';
1966
1971
  }
1967
1972
 
@@ -1974,7 +1979,7 @@ SVGElement.prototype = {
1974
1979
 
1975
1980
  // No reason to polyfill, we've got native support
1976
1981
  if (supports) {
1977
- css(elem, styles); // Apply altered textShadow or textRendering workaround
1982
+ this.css(styles); // Apply altered textShadow or textRendering workaround
1978
1983
  } else {
1979
1984
 
1980
1985
  this.fakeTS = true; // Fake text shadow
@@ -2250,7 +2255,7 @@ SVGElement.prototype = {
2250
2255
  }
2251
2256
 
2252
2257
  // serialize and set style attribute
2253
- if (isIE && !hasSVG) {
2258
+ if (isMS && !hasSVG) {
2254
2259
  css(elemWrapper.element, styles);
2255
2260
  } else {
2256
2261
  /*jslint unparam: true*/
@@ -2306,7 +2311,21 @@ SVGElement.prototype = {
2306
2311
  * [centerX, centerY, diameter] in pixels.
2307
2312
  */
2308
2313
  setRadialReference: function (coordinates) {
2314
+ var existingGradient = this.renderer.gradients[this.element.gradient];
2315
+
2309
2316
  this.element.radialReference = coordinates;
2317
+
2318
+ // On redrawing objects with an existing gradient, the gradient needs
2319
+ // to be repositioned (#3801)
2320
+ if (existingGradient && existingGradient.radAttr) {
2321
+ existingGradient.animate(
2322
+ this.renderer.getRadialAttr(
2323
+ coordinates,
2324
+ existingGradient.radAttr
2325
+ )
2326
+ );
2327
+ }
2328
+
2310
2329
  return this;
2311
2330
  },
2312
2331
 
@@ -2560,7 +2579,7 @@ SVGElement.prototype = {
2560
2579
  height = bBox.height;
2561
2580
 
2562
2581
  // Workaround for wrong bounding box in IE9 and IE10 (#1101, #1505, #1669, #2568)
2563
- if (isIE && styles && styles.fontSize === '11px' && height.toPrecision(3) === '16.9') {
2582
+ if (isMS && styles && styles.fontSize === '11px' && height.toPrecision(3) === '16.9') {
2564
2583
  bBox.height = height = 14;
2565
2584
  }
2566
2585
 
@@ -2870,7 +2889,7 @@ SVGElement.prototype = {
2870
2889
  // IE9-11 doesn't handle visibilty:inherit well, so we remove the attribute instead (#2881, #3909)
2871
2890
  if (value === 'inherit') {
2872
2891
  element.removeAttribute(key);
2873
- } else {
2892
+ } else {
2874
2893
  element.setAttribute(key, value);
2875
2894
  }
2876
2895
  },
@@ -2974,7 +2993,7 @@ SVGRenderer.prototype = {
2974
2993
  * @param {Number} height
2975
2994
  * @param {Boolean} forExport
2976
2995
  */
2977
- init: function (container, width, height, style, forExport) {
2996
+ init: function (container, width, height, style, forExport, allowHTML) {
2978
2997
  var renderer = this,
2979
2998
  loc = location,
2980
2999
  boxWrapper,
@@ -3014,6 +3033,7 @@ SVGRenderer.prototype = {
3014
3033
 
3015
3034
 
3016
3035
  renderer.defs = this.createElement('defs').add();
3036
+ renderer.allowHTML = allowHTML;
3017
3037
  renderer.forExport = forExport;
3018
3038
  renderer.gradients = {}; // Object where gradient SvgElements are stored
3019
3039
  renderer.cache = {}; // Cache for numerical bounding boxes
@@ -3108,6 +3128,17 @@ SVGRenderer.prototype = {
3108
3128
  */
3109
3129
  draw: function () {},
3110
3130
 
3131
+ /**
3132
+ * Get converted radial gradient attributes
3133
+ */
3134
+ getRadialAttr: function (radialReference, gradAttr) {
3135
+ return {
3136
+ cx: (radialReference[0] - radialReference[2] / 2) + gradAttr.cx * radialReference[2],
3137
+ cy: (radialReference[1] - radialReference[2] / 2) + gradAttr.cy * radialReference[2],
3138
+ r: gradAttr.r * radialReference[2]
3139
+ };
3140
+ },
3141
+
3111
3142
  /**
3112
3143
  * Parse a simple HTML string into SVG tspans
3113
3144
  *
@@ -3468,13 +3499,13 @@ SVGRenderer.prototype = {
3468
3499
  delete disabledState.style;
3469
3500
 
3470
3501
  // Add the events. IE9 and IE10 need mouseover and mouseout to funciton (#667).
3471
- addEvent(label.element, isIE ? 'mouseover' : 'mouseenter', function () {
3502
+ addEvent(label.element, isMS ? 'mouseover' : 'mouseenter', function () {
3472
3503
  if (curState !== 3) {
3473
3504
  label.attr(hoverState)
3474
3505
  .css(hoverStyle);
3475
3506
  }
3476
3507
  });
3477
- addEvent(label.element, isIE ? 'mouseout' : 'mouseleave', function () {
3508
+ addEvent(label.element, isMS ? 'mouseout' : 'mouseleave', function () {
3478
3509
  if (curState !== 3) {
3479
3510
  stateOptions = [normalState, hoverState, pressedState][curState];
3480
3511
  stateStyle = [normalStyle, hoverStyle, pressedStyle][curState];
@@ -3800,7 +3831,24 @@ SVGRenderer.prototype = {
3800
3831
  // the created element must be assigned to a variable in order to load (#292).
3801
3832
  imageElement = createElement('img', {
3802
3833
  onload: function () {
3834
+
3835
+ // Special case for SVGs on IE11, the width is not accessible until the image is
3836
+ // part of the DOM (#2854).
3837
+ if (this.width === 0) {
3838
+ css(this, {
3839
+ position: ABSOLUTE,
3840
+ top: '-999em'
3841
+ });
3842
+ document.body.appendChild(this);
3843
+ }
3844
+
3845
+ // Center the image
3803
3846
  centerImage(obj, symbolSizes[imageSrc] = [this.width, this.height]);
3847
+
3848
+ // Clean up after #2854 workaround.
3849
+ if (this.parentNode) {
3850
+ this.parentNode.removeChild(this);
3851
+ }
3804
3852
  },
3805
3853
  src: imageSrc
3806
3854
  });
@@ -4000,7 +4048,7 @@ SVGRenderer.prototype = {
4000
4048
  wrapper,
4001
4049
  attr = {};
4002
4050
 
4003
- if (useHTML && !renderer.forExport) {
4051
+ if (useHTML && (renderer.allowHTML || !renderer.forExport)) {
4004
4052
  return renderer.html(str, x, y);
4005
4053
  }
4006
4054
 
@@ -4051,7 +4099,7 @@ SVGRenderer.prototype = {
4051
4099
  style;
4052
4100
 
4053
4101
  fontSize = fontSize || this.style.fontSize;
4054
- if (elem && win.getComputedStyle) {
4102
+ if (!fontSize && elem && win.getComputedStyle) {
4055
4103
  elem = elem.element || elem; // SVGElement
4056
4104
  style = win.getComputedStyle(elem, "");
4057
4105
  fontSize = style && style.fontSize; // #4309, the style doesn't exist inside a hidden iframe in Firefox
@@ -4525,7 +4573,7 @@ extend(SVGElement.prototype, {
4525
4573
  */
4526
4574
  setSpanRotation: function (rotation, alignCorrection, baseline) {
4527
4575
  var rotationStyle = {},
4528
- cssTransformKey = isIE ? '-ms-transform' : isWebKit ? '-webkit-transform' : isFirefox ? 'MozTransform' : isOpera ? '-o-transform' : '';
4576
+ cssTransformKey = isMS ? '-ms-transform' : isWebKit ? '-webkit-transform' : isFirefox ? 'MozTransform' : isOpera ? '-o-transform' : '';
4529
4577
 
4530
4578
  rotationStyle[cssTransformKey] = rotationStyle.transform = 'rotate(' + rotation + 'deg)';
4531
4579
  rotationStyle[cssTransformKey + (isFirefox ? 'Origin' : '-origin')] = rotationStyle.transformOrigin = (alignCorrection * 100) + '% ' + baseline + 'px';
@@ -4652,9 +4700,14 @@ extend(SVGRenderer.prototype, {
4652
4700
  parentGroup.doTransform = true;
4653
4701
  }
4654
4702
  });
4655
- wrap(parentGroup, 'visibilitySetter', function (proceed, value, key, elem) {
4656
- proceed.call(this, value, key, elem);
4657
- htmlGroupStyle[key] = value;
4703
+
4704
+ // These properties are set as attributes on the SVG group, and as
4705
+ // identical CSS properties on the div. (#3542)
4706
+ each(['opacity', 'visibility'], function (prop) {
4707
+ wrap(parentGroup, prop + 'Setter', function (proceed, value, key, elem) {
4708
+ proceed.call(this, value, key, elem);
4709
+ htmlGroupStyle[key] = value;
4710
+ });
4658
4711
  });
4659
4712
  });
4660
4713
 
@@ -6543,6 +6596,7 @@ Axis.prototype = {
6543
6596
  //y: 0
6544
6597
  },
6545
6598
  type: 'linear' // linear, logarithmic or datetime
6599
+ //visible: true
6546
6600
  },
6547
6601
 
6548
6602
  /**
@@ -6676,10 +6730,9 @@ Axis.prototype = {
6676
6730
 
6677
6731
  //axis.axisTitleMargin = UNDEFINED,// = options.title.margin,
6678
6732
  axis.minPixelPadding = 0;
6679
- //axis.ignoreMinPadding = UNDEFINED; // can be set to true by a column or bar series
6680
- //axis.ignoreMaxPadding = UNDEFINED;
6681
6733
 
6682
6734
  axis.reversed = options.reversed;
6735
+ axis.visible = options.visible !== false;
6683
6736
  axis.zoomEnabled = options.zoomEnabled !== false;
6684
6737
 
6685
6738
  // Initial categories
@@ -6875,7 +6928,8 @@ Axis.prototype = {
6875
6928
  axis.hasVisibleSeries = false;
6876
6929
 
6877
6930
  // Reset properties in case we're redrawing (#3353)
6878
- axis.dataMin = axis.dataMax = axis.ignoreMinPadding = axis.ignoreMaxPadding = null;
6931
+ axis.dataMin = axis.dataMax = axis.threshold = null;
6932
+ axis.softThreshold = !axis.isXAxis;
6879
6933
 
6880
6934
  if (axis.buildStacks) {
6881
6935
  axis.buildStacks();
@@ -6925,13 +6979,11 @@ Axis.prototype = {
6925
6979
 
6926
6980
  // Adjust to threshold
6927
6981
  if (defined(threshold)) {
6928
- if (axis.dataMin >= threshold) {
6929
- axis.dataMin = threshold;
6930
- axis.ignoreMinPadding = true;
6931
- } else if (axis.dataMax < threshold) {
6932
- axis.dataMax = threshold;
6933
- axis.ignoreMaxPadding = true;
6934
- }
6982
+ axis.threshold = threshold;
6983
+ }
6984
+ // If any series has a hard threshold, it takes precedence
6985
+ if (!seriesOptions.softThreshold || axis.isLog) {
6986
+ axis.softThreshold = false;
6935
6987
  }
6936
6988
  }
6937
6989
  }
@@ -7176,7 +7228,8 @@ Axis.prototype = {
7176
7228
  xData,
7177
7229
  loopLength,
7178
7230
  minArgs,
7179
- maxArgs;
7231
+ maxArgs,
7232
+ minRange;
7180
7233
 
7181
7234
  // Set the automatic minimum range based on the closest point distance
7182
7235
  if (axis.isXAxis && axis.minRange === UNDEFINED && !axis.isLog) {
@@ -7204,7 +7257,7 @@ Axis.prototype = {
7204
7257
 
7205
7258
  // if minRange is exceeded, adjust
7206
7259
  if (max - min < axis.minRange) {
7207
- var minRange = axis.minRange;
7260
+ minRange = axis.minRange;
7208
7261
  zoomOffset = (minRange - max + min) / 2;
7209
7262
 
7210
7263
  // if min and max options have been set, don't go beyond it
@@ -7262,9 +7315,6 @@ Axis.prototype = {
7262
7315
  pointPlacement = series.options.pointPlacement,
7263
7316
  seriesClosestPointRange = series.closestPointRange;
7264
7317
 
7265
- if (seriesPointRange > range) { // #1446
7266
- seriesPointRange = 0;
7267
- }
7268
7318
  pointRange = mathMax(pointRange, seriesPointRange);
7269
7319
 
7270
7320
  if (!axis.single) {
@@ -7341,13 +7391,23 @@ Axis.prototype = {
7341
7391
  tickIntervalOption = options.tickInterval,
7342
7392
  minTickInterval,
7343
7393
  tickPixelIntervalOption = options.tickPixelInterval,
7344
- categories = axis.categories;
7394
+ categories = axis.categories,
7395
+ threshold = axis.threshold,
7396
+ softThreshold = axis.softThreshold,
7397
+ thresholdMin,
7398
+ thresholdMax,
7399
+ hardMin,
7400
+ hardMax;
7345
7401
 
7346
7402
  if (!isDatetimeAxis && !categories && !isLinked) {
7347
7403
  this.getTickAmount();
7348
7404
  }
7349
7405
 
7350
- // linked axis gets the extremes from the parent axis
7406
+ // Min or max set either by zooming/setExtremes or initial options
7407
+ hardMin = pick(axis.userMin, options.min);
7408
+ hardMax = pick(axis.userMax, options.max);
7409
+
7410
+ // Linked axis gets the extremes from the parent axis
7351
7411
  if (isLinked) {
7352
7412
  axis.linkedParent = chart[axis.coll][options.linkedTo];
7353
7413
  linkedParentExtremes = axis.linkedParent.getExtremes();
@@ -7356,9 +7416,24 @@ Axis.prototype = {
7356
7416
  if (options.type !== axis.linkedParent.options.type) {
7357
7417
  error(11, 1); // Can't link axes of different type
7358
7418
  }
7359
- } else { // initial min and max from the extreme data values
7360
- axis.min = pick(axis.userMin, options.min, axis.dataMin);
7361
- axis.max = pick(axis.userMax, options.max, axis.dataMax);
7419
+
7420
+ // Initial min and max from the extreme data values
7421
+ } else {
7422
+
7423
+ // Adjust to hard threshold
7424
+ if (!softThreshold && defined(threshold)) {
7425
+ if (axis.dataMin >= threshold) {
7426
+ thresholdMin = threshold;
7427
+ minPadding = 0;
7428
+ } else if (axis.dataMax <= threshold) {
7429
+ thresholdMax = threshold;
7430
+ maxPadding = 0;
7431
+ }
7432
+ }
7433
+
7434
+ axis.min = pick(hardMin, thresholdMin, axis.dataMin);
7435
+ axis.max = pick(hardMax, thresholdMax, axis.dataMax);
7436
+
7362
7437
  }
7363
7438
 
7364
7439
  if (isLog) {
@@ -7374,8 +7449,8 @@ Axis.prototype = {
7374
7449
 
7375
7450
  // handle zoomed range
7376
7451
  if (axis.range && defined(axis.max)) {
7377
- axis.userMin = axis.min = mathMax(axis.min, axis.minFromRange()); // #618
7378
- axis.userMax = axis.max;
7452
+ axis.userMin = axis.min = hardMin = mathMax(axis.min, axis.minFromRange()); // #618
7453
+ axis.userMax = hardMax = axis.max;
7379
7454
 
7380
7455
  axis.range = null; // don't use it when running setExtremes
7381
7456
  }
@@ -7393,10 +7468,10 @@ Axis.prototype = {
7393
7468
  if (!categories && !axis.axisPointRange && !axis.usePercentage && !isLinked && defined(axis.min) && defined(axis.max)) {
7394
7469
  length = axis.max - axis.min;
7395
7470
  if (length) {
7396
- if (!defined(options.min) && !defined(axis.userMin) && minPadding && (axis.dataMin < 0 || !axis.ignoreMinPadding)) {
7471
+ if (!defined(hardMin) && minPadding) {
7397
7472
  axis.min -= length * minPadding;
7398
7473
  }
7399
- if (!defined(options.max) && !defined(axis.userMax) && maxPadding && (axis.dataMax > 0 || !axis.ignoreMaxPadding)) {
7474
+ if (!defined(hardMax) && maxPadding) {
7400
7475
  axis.max += length * maxPadding;
7401
7476
  }
7402
7477
  }
@@ -7410,6 +7485,21 @@ Axis.prototype = {
7410
7485
  axis.max = mathMin(axis.max, options.ceiling);
7411
7486
  }
7412
7487
 
7488
+ // When the threshold is soft, adjust the extreme value only if
7489
+ // the data extreme and the padded extreme land on either side of the threshold. For example,
7490
+ // a series of [0, 1, 2, 3] would make the yAxis add a tick for -1 because of the
7491
+ // default minPadding and startOnTick options. This is prevented by the softThreshold
7492
+ // option.
7493
+ if (softThreshold && defined(axis.dataMin)) {
7494
+ threshold = threshold || 0;
7495
+ if (!defined(hardMin) && axis.min < threshold && axis.dataMin >= threshold) {
7496
+ axis.min = threshold;
7497
+ } else if (!defined(hardMax) && axis.max > threshold && axis.dataMax <= threshold) {
7498
+ axis.max = threshold;
7499
+ }
7500
+ }
7501
+
7502
+
7413
7503
  // get tickInterval
7414
7504
  if (axis.min === axis.max || axis.min === undefined || axis.max === undefined) {
7415
7505
  axis.tickInterval = 1;
@@ -7609,12 +7699,12 @@ Axis.prototype = {
7609
7699
  horiz = axis.horiz,
7610
7700
  key = [horiz ? options.left : options.top, horiz ? options.width : options.height, options.pane].join(',');
7611
7701
 
7612
- if (others[key]) {
7613
- if (axis.series.length) {
7702
+ if (axis.series.length) { // #4442
7703
+ if (others[key]) {
7614
7704
  hasOther = true; // #4201
7705
+ } else {
7706
+ others[key] = 1;
7615
7707
  }
7616
- } else {
7617
- others[key] = 1;
7618
7708
  }
7619
7709
  });
7620
7710
 
@@ -7927,9 +8017,11 @@ Axis.prototype = {
7927
8017
  };
7928
8018
 
7929
8019
  if (horiz) {
7930
- autoRotation = defined(rotationOption) ?
7931
- [rotationOption] :
7932
- slotSize < pick(labelOptions.autoRotationLimit, 80) && !labelOptions.staggerLines && !labelOptions.step && labelOptions.autoRotation;
8020
+ autoRotation = !labelOptions.staggerLines && !labelOptions.step && ( // #3971
8021
+ defined(rotationOption) ?
8022
+ [rotationOption] :
8023
+ slotSize < pick(labelOptions.autoRotationLimit, 80) && labelOptions.autoRotation
8024
+ );
7933
8025
 
7934
8026
  if (autoRotation) {
7935
8027
 
@@ -7958,7 +8050,7 @@ Axis.prototype = {
7958
8050
  }
7959
8051
 
7960
8052
  this.autoRotation = autoRotation;
7961
- this.labelRotation = rotation;
8053
+ this.labelRotation = pick(rotation, rotationOption);
7962
8054
 
7963
8055
  return newTickInterval;
7964
8056
  },
@@ -8054,11 +8146,11 @@ Axis.prototype = {
8054
8146
  var tick = ticks[pos],
8055
8147
  label = tick && tick.label;
8056
8148
  if (label) {
8149
+ label.attr(attr); // This needs to go before the CSS in old IE (#4502)
8057
8150
  if (css) {
8058
8151
  label.css(merge(css, label.specCss));
8059
8152
  }
8060
8153
  delete label.specCss;
8061
- label.attr(attr);
8062
8154
  tick.rotation = attr.rotation;
8063
8155
  }
8064
8156
  });
@@ -8101,6 +8193,7 @@ Axis.prototype = {
8101
8193
  clip,
8102
8194
  directionFactor = [-1, 1, 1, -1][side],
8103
8195
  n,
8196
+ axisParent = axis.axisParent, // Used in color axis
8104
8197
  lineHeightCorrection;
8105
8198
 
8106
8199
  // For reuse in Axis.render
@@ -8114,14 +8207,14 @@ Axis.prototype = {
8114
8207
  if (!axis.axisGroup) {
8115
8208
  axis.gridGroup = renderer.g('grid')
8116
8209
  .attr({ zIndex: options.gridZIndex || 1 })
8117
- .add();
8210
+ .add(axisParent);
8118
8211
  axis.axisGroup = renderer.g('axis')
8119
8212
  .attr({ zIndex: options.zIndex || 2 })
8120
- .add();
8213
+ .add(axisParent);
8121
8214
  axis.labelGroup = renderer.g('axis-labels')
8122
8215
  .attr({ zIndex: labelOptions.zIndex || 7 })
8123
8216
  .addClass(PREFIX + axis.coll.toLowerCase() + '-labels')
8124
- .add();
8217
+ .add(axisParent);
8125
8218
  }
8126
8219
 
8127
8220
  if (hasData || axis.isLinked) {
@@ -8381,12 +8474,12 @@ Axis.prototype = {
8381
8474
  // alternate grid color
8382
8475
  if (alternateGridColor) {
8383
8476
  each(tickPositions, function (pos, i) {
8384
- if (i % 2 === 0 && pos < axis.max) {
8477
+ to = tickPositions[i + 1] !== UNDEFINED ? tickPositions[i + 1] + tickmarkOffset : axis.max - tickmarkOffset;
8478
+ if (i % 2 === 0 && pos < axis.max && to <= axis.max - tickmarkOffset) { // #2248
8385
8479
  if (!alternateBands[pos]) {
8386
8480
  alternateBands[pos] = new Highcharts.PlotLineOrBand(axis);
8387
8481
  }
8388
8482
  from = pos + tickmarkOffset; // #949
8389
- to = tickPositions[i + 1] !== UNDEFINED ? tickPositions[i + 1] + tickmarkOffset : axis.max;
8390
8483
  alternateBands[pos].options = {
8391
8484
  from: isLog ? lin2log(from) : from,
8392
8485
  to: isLog ? lin2log(to) : to,
@@ -8488,13 +8581,15 @@ Axis.prototype = {
8488
8581
  */
8489
8582
  redraw: function () {
8490
8583
 
8491
- // render the axis
8492
- this.render();
8584
+ if (this.visible) {
8585
+ // render the axis
8586
+ this.render();
8493
8587
 
8494
- // move plot lines and bands
8495
- each(this.plotLinesAndBands, function (plotLine) {
8496
- plotLine.render();
8497
- });
8588
+ // move plot lines and bands
8589
+ each(this.plotLinesAndBands, function (plotLine) {
8590
+ plotLine.render();
8591
+ });
8592
+ }
8498
8593
 
8499
8594
  // mark associated series as dirty and ready for redraw
8500
8595
  each(this.series, function (series) {
@@ -9579,9 +9674,10 @@ Pointer.prototype = {
9579
9674
  hoverPoint = chart.hoverPoint,
9580
9675
  hoverSeries = chart.hoverSeries,
9581
9676
  i,
9582
- distance = chart.chartWidth,
9677
+ distance = Number.MAX_VALUE, // #4511
9583
9678
  anchor,
9584
9679
  noSharedTooltip,
9680
+ stickToHoverSeries,
9585
9681
  directTouch,
9586
9682
  kdpoints = [],
9587
9683
  kdpoint,
@@ -9597,9 +9693,11 @@ Pointer.prototype = {
9597
9693
  }
9598
9694
  }
9599
9695
 
9600
- // If it has a hoverPoint and that series requires direct touch (like columns),
9601
- // use the hoverPoint (#3899). Otherwise, search the k-d tree.
9602
- if (!shared && hoverSeries && hoverSeries.directTouch && hoverPoint) {
9696
+ // If it has a hoverPoint and that series requires direct touch (like columns, #3899), or we're on
9697
+ // a noSharedTooltip series among shared tooltip series (#4546), use the hoverPoint . Otherwise,
9698
+ // search the k-d tree.
9699
+ stickToHoverSeries = hoverSeries && (shared ? hoverSeries.noSharedTooltip : hoverSeries.directTouch);
9700
+ if (stickToHoverSeries && hoverPoint) {
9603
9701
  kdpoint = hoverPoint;
9604
9702
 
9605
9703
  // Handle shared tooltip or cases where a series is not yet hovered
@@ -10042,11 +10140,11 @@ Pointer.prototype = {
10042
10140
 
10043
10141
  onTrackerMouseOut: function (e) {
10044
10142
  var series = this.chart.hoverSeries,
10045
- relatedTarget = e.relatedTarget || e.toElement,
10046
- relatedSeries = relatedTarget && relatedTarget.point && relatedTarget.point.series; // #2499
10143
+ relatedTarget = e.relatedTarget || e.toElement;
10047
10144
 
10048
- if (series && !series.options.stickyTracking && !this.inClass(relatedTarget, PREFIX + 'tooltip') &&
10049
- relatedSeries !== series) {
10145
+ if (series && !series.options.stickyTracking &&
10146
+ !this.inClass(relatedTarget, PREFIX + 'tooltip') &&
10147
+ !this.inClass(relatedTarget, PREFIX + 'series-' + series.index)) { // #2499, #4465
10050
10148
  series.onMouseOut();
10051
10149
  }
10052
10150
  },
@@ -11751,7 +11849,7 @@ Chart.prototype = {
11751
11849
  subtitle
11752
11850
  .css({ width: (subtitleOptions.width || autoWidth) + PX })
11753
11851
  .align(extend({
11754
- y: titleOffset + (titleOptions.margin - 13) + renderer.fontMetrics(titleOptions.style.fontSize, subtitle).b
11852
+ y: titleOffset + (titleOptions.margin - 13) + renderer.fontMetrics(subtitleOptions.style.fontSize, title).b
11755
11853
  }, subtitleOptions), false, 'spacingBox');
11756
11854
 
11757
11855
  if (!subtitleOptions.floating && !subtitleOptions.verticalAlign) {
@@ -11839,12 +11937,14 @@ Chart.prototype = {
11839
11937
  getContainer: function () {
11840
11938
  var chart = this,
11841
11939
  container,
11842
- optionsChart = chart.options.chart,
11940
+ options = chart.options,
11941
+ optionsChart = options.chart,
11843
11942
  chartWidth,
11844
11943
  chartHeight,
11845
11944
  renderTo,
11846
11945
  indexAttrName = 'data-highcharts-chart',
11847
11946
  oldChartIndex,
11947
+ Ren,
11848
11948
  containerId;
11849
11949
 
11850
11950
  chart.renderTo = renderTo = optionsChart.renderTo;
@@ -11911,10 +12011,15 @@ Chart.prototype = {
11911
12011
  chart._cursor = container.style.cursor;
11912
12012
 
11913
12013
  // Initialize the renderer
11914
- chart.renderer =
11915
- optionsChart.forExport ? // force SVG, used for SVG export
11916
- new SVGRenderer(container, chartWidth, chartHeight, optionsChart.style, true) :
11917
- new Renderer(container, chartWidth, chartHeight, optionsChart.style);
12014
+ Ren = Highcharts[optionsChart.renderer] || Renderer;
12015
+ chart.renderer = new Ren(
12016
+ container,
12017
+ chartWidth,
12018
+ chartHeight,
12019
+ optionsChart.style,
12020
+ optionsChart.forExport,
12021
+ options.exporting && options.exporting.allowHTML
12022
+ );
11918
12023
 
11919
12024
  if (useCanVG) {
11920
12025
  // If we need canvg library, extend and configure the renderer
@@ -11967,7 +12072,9 @@ Chart.prototype = {
11967
12072
  // pre-render axes to get labels offset width
11968
12073
  if (chart.hasCartesianSeries) {
11969
12074
  each(chart.axes, function (axis) {
11970
- axis.getOffset();
12075
+ if (axis.visible) {
12076
+ axis.getOffset();
12077
+ }
11971
12078
  });
11972
12079
  }
11973
12080
 
@@ -12043,7 +12150,7 @@ Chart.prototype = {
12043
12150
  chartHeight,
12044
12151
  fireEndResize,
12045
12152
  renderer = chart.renderer,
12046
- globalAnimation = renderer.globalAnimation;
12153
+ globalAnimation;
12047
12154
 
12048
12155
  // Handle the isResizing counter
12049
12156
  chart.isResizing += 1;
@@ -12069,6 +12176,7 @@ Chart.prototype = {
12069
12176
  }
12070
12177
 
12071
12178
  // Resize the container with the global animation applied if enabled (#2503)
12179
+ globalAnimation = renderer.globalAnimation;
12072
12180
  (globalAnimation ? animate : css)(chart.container, {
12073
12181
  width: chartWidth + PX,
12074
12182
  height: chartHeight + PX
@@ -12101,8 +12209,8 @@ Chart.prototype = {
12101
12209
  chart.oldChartHeight = null;
12102
12210
  fireEvent(chart, 'resize');
12103
12211
 
12104
- // fire endResize and set isResizing back
12105
- // If animation is disabled, fire without delay
12212
+ // Fire endResize and set isResizing back. If animation is disabled, fire without delay
12213
+ globalAnimation = renderer.globalAnimation; // Reassign it before using it, it may have changed since the top of this function.
12106
12214
  if (globalAnimation === false) {
12107
12215
  fireEndResize();
12108
12216
  } else { // else set a timeout with the animation duration
@@ -12468,7 +12576,9 @@ Chart.prototype = {
12468
12576
  // Axes
12469
12577
  if (chart.hasCartesianSeries) {
12470
12578
  each(axes, function (axis) {
12471
- axis.render();
12579
+ if (axis.visible) {
12580
+ axis.render();
12581
+ }
12472
12582
  });
12473
12583
  }
12474
12584
 
@@ -12720,6 +12830,10 @@ var CenteredSeriesMixin = Highcharts.CenteredSeriesMixin = {
12720
12830
  (handleSlicingRoom ? slicingRoom : 0);
12721
12831
 
12722
12832
  }
12833
+ // innerSize cannot be larger than size (#3632)
12834
+ if (positions[3] > positions[2]) {
12835
+ positions[3] = positions[2];
12836
+ }
12723
12837
  return positions;
12724
12838
  }
12725
12839
  };
@@ -12815,7 +12929,11 @@ Point.prototype = {
12815
12929
  i++;
12816
12930
  }
12817
12931
  while (j < valueCount) {
12818
- ret[pointArrayMap[j++]] = options[i++];
12932
+ if (!keys || options[i] !== undefined) { // Skip undefined positions for keys
12933
+ ret[pointArrayMap[j]] = options[i];
12934
+ }
12935
+ i++;
12936
+ j++;
12819
12937
  }
12820
12938
  } else if (typeof options === 'object') {
12821
12939
  ret = options;
@@ -12880,7 +12998,7 @@ Point.prototype = {
12880
12998
  */
12881
12999
  destroyElements: function () {
12882
13000
  var point = this,
12883
- props = ['graphic', 'dataLabel', 'dataLabelUpper', 'group', 'connector', 'shadowGroup'],
13001
+ props = ['graphic', 'dataLabel', 'dataLabelUpper', 'connector', 'shadowGroup'],
12884
13002
  prop,
12885
13003
  i = 6;
12886
13004
  while (i--) {
@@ -12964,7 +13082,8 @@ Point.prototype = {
12964
13082
  }
12965
13083
 
12966
13084
  fireEvent(this, eventType, eventArgs, defaultFunction);
12967
- }
13085
+ },
13086
+ visible: true
12968
13087
  };/**
12969
13088
  * @classDescription The base function which all other series types inherit from. The data in the series is stored
12970
13089
  * in various arrays.
@@ -12999,6 +13118,7 @@ Series.prototype = {
12999
13118
  fill: 'fillColor',
13000
13119
  r: 'radius'
13001
13120
  },
13121
+ directTouch: false,
13002
13122
  axisTypes: ['xAxis', 'yAxis'],
13003
13123
  colorCounter: 0,
13004
13124
  parallelArrays: ['x', 'y'], // each point's x and y values are stored in this.xData and this.yData
@@ -13448,6 +13568,13 @@ Series.prototype = {
13448
13568
  animation = false;
13449
13569
  }
13450
13570
 
13571
+ // Typically for pie series, points need to be processed and generated
13572
+ // prior to rendering the legend
13573
+ if (options.legendType === 'point') { // docs: legendType now supported on more series types (at least column and pie)
13574
+ this.processData();
13575
+ this.generatePoints();
13576
+ }
13577
+
13451
13578
  if (redraw) {
13452
13579
  chart.redraw(animation);
13453
13580
  }
@@ -13471,6 +13598,7 @@ Series.prototype = {
13471
13598
  i, // loop variable
13472
13599
  options = series.options,
13473
13600
  cropThreshold = options.cropThreshold,
13601
+ getExtremesFromAll = series.getExtremesFromAll || options.getExtremesFromAll, // #4599
13474
13602
  isCartesian = series.isCartesian,
13475
13603
  xExtremes,
13476
13604
  min,
@@ -13489,7 +13617,7 @@ Series.prototype = {
13489
13617
  }
13490
13618
 
13491
13619
  // optionally filter out points outside the plot area
13492
- if (isCartesian && series.sorted && (!cropThreshold || dataLength > cropThreshold || series.forceCrop)) {
13620
+ if (isCartesian && series.sorted && !getExtremesFromAll && (!cropThreshold || dataLength > cropThreshold || series.forceCrop)) {
13493
13621
 
13494
13622
  // it's outside current extremes
13495
13623
  if (processedXData[dataLength - 1] < min || processedXData[0] > max) {
@@ -13709,6 +13837,7 @@ Series.prototype = {
13709
13837
  plotX,
13710
13838
  plotY,
13711
13839
  lastPlotX,
13840
+ stackIndicator,
13712
13841
  closestPointRangePx = Number.MAX_VALUE;
13713
13842
 
13714
13843
  // Translate each point
@@ -13733,9 +13862,9 @@ Series.prototype = {
13733
13862
 
13734
13863
  // Calculate the bottom y value for stacked series
13735
13864
  if (stacking && series.visible && stack && stack[xValue]) {
13736
-
13865
+ stackIndicator = series.getStackIndicator(stackIndicator, xValue, series.index);
13737
13866
  pointStack = stack[xValue];
13738
- stackValues = pointStack.points[series.index + ',' + i];
13867
+ stackValues = pointStack.points[stackIndicator.key];
13739
13868
  yBottom = stackValues[0];
13740
13869
  yValue = stackValues[1];
13741
13870
 
@@ -13802,11 +13931,12 @@ Series.prototype = {
13802
13931
  */
13803
13932
  setClip: function (animation) {
13804
13933
  var chart = this.chart,
13934
+ options = this.options,
13805
13935
  renderer = chart.renderer,
13806
13936
  inverted = chart.inverted,
13807
13937
  seriesClipBox = this.clipBox,
13808
13938
  clipBox = seriesClipBox || chart.clipBox,
13809
- sharedClipKey = this.sharedClipKey || ['_sharedClip', animation && animation.duration, animation && animation.easing, clipBox.height].join(','),
13939
+ sharedClipKey = this.sharedClipKey || ['_sharedClip', animation && animation.duration, animation && animation.easing, clipBox.height, options.xAxis, options.yAxis].join(','), // #4526
13810
13940
  clipRect = chart[sharedClipKey],
13811
13941
  markerClipRect = chart[sharedClipKey + 'm'];
13812
13942
 
@@ -13831,7 +13961,7 @@ Series.prototype = {
13831
13961
  clipRect.count += 1;
13832
13962
  }
13833
13963
 
13834
- if (this.options.clip !== false) {
13964
+ if (options.clip !== false) {
13835
13965
  this.group.clip(animation || seriesClipBox ? clipRect : chart.clipRect);
13836
13966
  this.markerGroup.clip(markerClipRect);
13837
13967
  this.sharedClipKey = sharedClipKey;
@@ -14097,9 +14227,8 @@ Series.prototype = {
14097
14227
  threshold = zones[++j];
14098
14228
  }
14099
14229
 
14100
- if (threshold.color) {
14101
- point.color = point.fillColor = threshold.color;
14102
- }
14230
+ point.color = point.fillColor = pick(threshold.color, series.color); // #3636, #4267, #4430 - inherit color from series, when color is undefined
14231
+
14103
14232
  }
14104
14233
 
14105
14234
  hasPointSpecificOptions = seriesOptions.colorByPoint || point.color; // #868
@@ -14122,9 +14251,9 @@ Series.prototype = {
14122
14251
  pointStateOptionsHover = stateOptions[HOVER_STATE] = stateOptions[HOVER_STATE] || {};
14123
14252
 
14124
14253
  // Handle colors for column and pies
14125
- if (!seriesOptions.marker) { // column, bar, point
14254
+ if (!seriesOptions.marker || (point.negative && !pointStateOptionsHover.fillColor && !stateOptionsHover.fillColor)) { // column, bar, point or negative threshold for series with markers (#3636)
14126
14255
  // If no hover color is given, brighten the normal color. #1619, #2579
14127
- pointStateOptionsHover.color = pointStateOptionsHover.color || (!point.options.color && stateOptionsHover[(point.negative && seriesNegativeColor ? 'negativeColor' : 'color')]) ||
14256
+ pointStateOptionsHover[series.pointAttrToOptions.fill] = pointStateOptionsHover.color || (!point.options.color && stateOptionsHover[(point.negative && seriesNegativeColor ? 'negativeColor' : 'color')]) ||
14128
14257
  Color(point.color)
14129
14258
  .brighten(pointStateOptionsHover.brightness || stateOptionsHover.brightness)
14130
14259
  .get();
@@ -14271,21 +14400,25 @@ Series.prototype = {
14271
14400
  if (step === 'right') {
14272
14401
  segmentPath.push(
14273
14402
  lastPoint.plotX,
14274
- plotY
14403
+ plotY,
14404
+ L
14275
14405
  );
14276
14406
 
14277
14407
  } else if (step === 'center') {
14278
14408
  segmentPath.push(
14279
14409
  (lastPoint.plotX + plotX) / 2,
14280
14410
  lastPoint.plotY,
14411
+ L,
14281
14412
  (lastPoint.plotX + plotX) / 2,
14282
- plotY
14413
+ plotY,
14414
+ L
14283
14415
  );
14284
14416
 
14285
14417
  } else {
14286
14418
  segmentPath.push(
14287
14419
  plotX,
14288
- lastPoint.plotY
14420
+ lastPoint.plotY,
14421
+ L
14289
14422
  );
14290
14423
  }
14291
14424
  }
@@ -14546,7 +14679,10 @@ Series.prototype = {
14546
14679
  zIndex: zIndex || 0.1 // IE8 needs this
14547
14680
  })
14548
14681
  .add(parent);
14682
+
14683
+ group.addClass('highcharts-series-' + this.index);
14549
14684
  }
14685
+
14550
14686
  // Place it on first and subsequent (redraw) calls
14551
14687
  group[isNew ? 'attr' : 'animate'](this.getPlotBox());
14552
14688
  return group;
@@ -15096,6 +15232,7 @@ Series.prototype.setStackedPoints = function () {
15096
15232
  yAxis = series.yAxis,
15097
15233
  stacks = yAxis.stacks,
15098
15234
  oldStacks = yAxis.oldStacks,
15235
+ stackIndicator,
15099
15236
  isNegative,
15100
15237
  stack,
15101
15238
  other,
@@ -15112,8 +15249,8 @@ Series.prototype.setStackedPoints = function () {
15112
15249
  for (i = 0; i < yDataLength; i++) {
15113
15250
  x = xData[i];
15114
15251
  y = yData[i];
15115
- pointKey = series.index + ',' + i;
15116
-
15252
+ stackIndicator = series.getStackIndicator(stackIndicator, x, series.index);
15253
+ pointKey = stackIndicator.key;
15117
15254
  // Read stacked values into a stack based on the x value,
15118
15255
  // the sign of y and the stack key. Stacking is also handled for null values (#739)
15119
15256
  isNegative = negStacks && y < (stackThreshold ? 0 : threshold);
@@ -15182,7 +15319,8 @@ Series.prototype.setPercentStacks = function () {
15182
15319
  var series = this,
15183
15320
  stackKey = series.stackKey,
15184
15321
  stacks = series.yAxis.stacks,
15185
- processedXData = series.processedXData;
15322
+ processedXData = series.processedXData,
15323
+ stackIndicator;
15186
15324
 
15187
15325
  each([stackKey, '-' + stackKey], function (key) {
15188
15326
  var i = processedXData.length,
@@ -15193,8 +15331,9 @@ Series.prototype.setPercentStacks = function () {
15193
15331
 
15194
15332
  while (i--) {
15195
15333
  x = processedXData[i];
15334
+ stackIndicator = series.getStackIndicator(stackIndicator, x, series.index);
15196
15335
  stack = stacks[key] && stacks[key][x];
15197
- pointExtremes = stack && stack.points[series.index + ',' + i];
15336
+ pointExtremes = stack && stack.points[stackIndicator.key];
15198
15337
  if (pointExtremes) {
15199
15338
  totalFactor = stack.total ? 100 / stack.total : 0;
15200
15339
  pointExtremes[0] = correctFloat(pointExtremes[0] * totalFactor); // Y bottom value
@@ -15205,6 +15344,24 @@ Series.prototype.setPercentStacks = function () {
15205
15344
  });
15206
15345
  };
15207
15346
 
15347
+ /**
15348
+ * Get stack indicator, according to it's x-value, to determine points with the same x-value
15349
+ */
15350
+ Series.prototype.getStackIndicator = function(stackIndicator, x, index) {
15351
+ if (!defined(stackIndicator) || stackIndicator.x !== x) {
15352
+ stackIndicator = {
15353
+ x: x,
15354
+ index: 0
15355
+ };
15356
+ } else {
15357
+ stackIndicator.index++;
15358
+ }
15359
+
15360
+ stackIndicator.key = [index, x, stackIndicator.index].join(',');
15361
+
15362
+ return stackIndicator;
15363
+ };
15364
+
15208
15365
  // Extend the Chart prototype for dynamic methods
15209
15366
  extend(Chart.prototype, {
15210
15367
 
@@ -15468,7 +15625,7 @@ extend(Series.prototype, {
15468
15625
  }
15469
15626
  each(shiftShapes, function (shape) {
15470
15627
  if (series[shape]) {
15471
- series[shape].shift = currentShift + 1;
15628
+ series[shape].shift = currentShift + (seriesOptions.step ? 2 : 1);
15472
15629
  }
15473
15630
  });
15474
15631
  }
@@ -15749,6 +15906,7 @@ seriesTypes.line = LineSeries;
15749
15906
  * Set the default options for area
15750
15907
  */
15751
15908
  defaultPlotOptions.area = merge(defaultSeriesOptions, {
15909
+ softThreshold: false,
15752
15910
  threshold: 0
15753
15911
  // trackByArea: false,
15754
15912
  // lineColor: null, // overrides color, but lets fillColor be unaltered
@@ -15779,6 +15937,7 @@ var AreaSeries = extendClass(Series, {
15779
15937
  plotY,
15780
15938
  points = this.points,
15781
15939
  connectNulls = this.options.connectNulls,
15940
+ stackIndicator,
15782
15941
  i,
15783
15942
  x;
15784
15943
 
@@ -15799,7 +15958,7 @@ var AreaSeries = extendClass(Series, {
15799
15958
  });
15800
15959
 
15801
15960
  each(keys, function (x) {
15802
- var y = 0,
15961
+ var threshold = null,
15803
15962
  stackPoint;
15804
15963
 
15805
15964
  if (connectNulls && (!pointMap[x] || pointMap[x].y === null)) { // #1836
@@ -15816,16 +15975,17 @@ var AreaSeries = extendClass(Series, {
15816
15975
 
15817
15976
  // Loop down the stack to find the series below this one that has
15818
15977
  // a value (#1991)
15819
- for (i = series.index; i <= yAxis.series.length; i++) {
15820
- stackPoint = stack[x].points[i + ',' + x];
15978
+ for (i = series.index; i <= yAxis.series.length; i++) {
15979
+ stackIndicator = series.getStackIndicator(null, x, i);
15980
+ stackPoint = stack[x].points[stackIndicator.key];
15821
15981
  if (stackPoint) {
15822
- y = stackPoint[1];
15982
+ threshold = stackPoint[1];
15823
15983
  break;
15824
15984
  }
15825
15985
  }
15826
15986
 
15827
15987
  plotX = xAxis.translate(x);
15828
- plotY = yAxis.toPixels(y, true);
15988
+ plotY = yAxis.getThreshold(threshold);
15829
15989
  segment.push({
15830
15990
  y: null,
15831
15991
  plotX: plotX,
@@ -16133,7 +16293,8 @@ defaultPlotOptions.column = merge(defaultSeriesOptions, {
16133
16293
  verticalAlign: null, // auto
16134
16294
  y: null
16135
16295
  },
16136
- startFromThreshold: true, // docs: http://jsfiddle.net/highcharts/hz8fopan/14/
16296
+ softThreshold: false,
16297
+ startFromThreshold: true, // docs (but false doesn't work well): http://jsfiddle.net/highcharts/hz8fopan/14/
16137
16298
  stickyTracking: false,
16138
16299
  tooltip: {
16139
16300
  distance: 6
@@ -16245,6 +16406,48 @@ var ColumnSeries = extendClass(Series, {
16245
16406
 
16246
16407
  },
16247
16408
 
16409
+ /**
16410
+ * Make the columns crisp. The edges are rounded to the nearest full pixel.
16411
+ */
16412
+ crispCol: function (x, y, w, h) {
16413
+ var chart = this.chart,
16414
+ borderWidth = this.borderWidth,
16415
+ xCrisp = -(borderWidth % 2 ? 0.5 : 0),
16416
+ yCrisp = borderWidth % 2 ? 0.5 : 1,
16417
+ right,
16418
+ bottom,
16419
+ fromTop;
16420
+
16421
+ if (chart.inverted && chart.renderer.isVML) {
16422
+ yCrisp += 1;
16423
+ }
16424
+
16425
+ // Horizontal. We need to first compute the exact right edge, then round it
16426
+ // and compute the width from there.
16427
+ right = Math.round(x + w) + xCrisp;
16428
+ x = Math.round(x) + xCrisp;
16429
+ w = right - x;
16430
+
16431
+ // Vertical
16432
+ fromTop = mathAbs(y) <= 0.5; // #4504
16433
+ bottom = Math.round(y + h) + yCrisp;
16434
+ y = Math.round(y) + yCrisp;
16435
+ h = bottom - y;
16436
+
16437
+ // Top edges are exceptions
16438
+ if (fromTop) {
16439
+ y -= 1;
16440
+ h += 1;
16441
+ }
16442
+
16443
+ return {
16444
+ x: x,
16445
+ y: y,
16446
+ width: w,
16447
+ height: h
16448
+ };
16449
+ },
16450
+
16248
16451
  /**
16249
16452
  * Translate each point to the plot area coordinate system and find shape positions
16250
16453
  */
@@ -16263,15 +16466,10 @@ var ColumnSeries = extendClass(Series, {
16263
16466
  metrics = series.getColumnMetrics(),
16264
16467
  pointWidth = metrics.width,
16265
16468
  seriesBarW = series.barW = mathMax(pointWidth, 1 + 2 * borderWidth), // postprocessed for border width
16266
- pointXOffset = series.pointXOffset = metrics.offset,
16267
- xCrisp = -(borderWidth % 2 ? 0.5 : 0),
16268
- yCrisp = borderWidth % 2 ? 0.5 : 1;
16469
+ pointXOffset = series.pointXOffset = metrics.offset;
16269
16470
 
16270
16471
  if (chart.inverted) {
16271
16472
  translatedThreshold -= 0.5; // #3355
16272
- if (chart.renderer.isVML) {
16273
- yCrisp += 1;
16274
- }
16275
16473
  }
16276
16474
 
16277
16475
  // When the pointPadding is 0, we want the columns to be packed tightly, so we allow individual
@@ -16285,15 +16483,12 @@ var ColumnSeries = extendClass(Series, {
16285
16483
 
16286
16484
  // Record the new values
16287
16485
  each(series.points, function (point) {
16288
- var yBottom = pick(point.yBottom, translatedThreshold),
16486
+ var yBottom = mathMin(pick(point.yBottom, translatedThreshold), 9e4), // #3575
16289
16487
  safeDistance = 999 + mathAbs(yBottom),
16290
16488
  plotY = mathMin(mathMax(-safeDistance, point.plotY), yAxis.len + safeDistance), // Don't draw too far outside plot area (#1303, #2241, #4264)
16291
16489
  barX = point.plotX + pointXOffset,
16292
16490
  barW = seriesBarW,
16293
16491
  barY = mathMin(plotY, yBottom),
16294
- right,
16295
- bottom,
16296
- fromTop,
16297
16492
  up,
16298
16493
  barH = mathMax(plotY, yBottom) - barY;
16299
16494
 
@@ -16302,10 +16497,9 @@ var ColumnSeries = extendClass(Series, {
16302
16497
  if (minPointLength) {
16303
16498
  barH = minPointLength;
16304
16499
  up = (!yAxis.reversed && !point.negative) || (yAxis.reversed && point.negative);
16305
- barY =
16306
- mathRound(mathAbs(barY - translatedThreshold) > minPointLength ? // stacked
16500
+ barY = mathAbs(barY - translatedThreshold) > minPointLength ? // stacked
16307
16501
  yBottom - minPointLength : // keep position
16308
- translatedThreshold - (up ? minPointLength : 0)); // #1485, #4051
16502
+ translatedThreshold - (up ? minPointLength : 0); // #1485, #4051
16309
16503
  }
16310
16504
  }
16311
16505
 
@@ -16313,22 +16507,6 @@ var ColumnSeries = extendClass(Series, {
16313
16507
  point.barX = barX;
16314
16508
  point.pointWidth = pointWidth;
16315
16509
 
16316
- // Round off to obtain crisp edges and avoid overlapping with neighbours (#2694)
16317
- right = mathRound(barX + barW) + xCrisp;
16318
- barX = mathRound(barX) + xCrisp;
16319
- barW = right - barX;
16320
-
16321
- fromTop = mathAbs(barY) < 0.5;
16322
- bottom = mathMin(mathRound(barY + barH) + yCrisp, 9e4); // #3575
16323
- barY = mathRound(barY) + yCrisp;
16324
- barH = bottom - barY;
16325
-
16326
- // Top edges are exceptions
16327
- if (fromTop) {
16328
- barY -= 1;
16329
- barH += 1;
16330
- }
16331
-
16332
16510
  // Fix the tooltip on center of grouped columns (#1216, #424, #3648)
16333
16511
  point.tooltipPos = chart.inverted ?
16334
16512
  [yAxis.len + yAxis.pos - chart.plotLeft - plotY, series.xAxis.len - barX - barW / 2, barH] :
@@ -16336,12 +16514,7 @@ var ColumnSeries = extendClass(Series, {
16336
16514
 
16337
16515
  // Register shape type and arguments to be used in drawPoints
16338
16516
  point.shapeType = 'rect';
16339
- point.shapeArgs = {
16340
- x: barX,
16341
- y: barY,
16342
- width: barW,
16343
- height: barH
16344
- };
16517
+ point.shapeArgs = series.crispCol(barX, barY, barW, barH);
16345
16518
  });
16346
16519
 
16347
16520
  },
@@ -16396,7 +16569,7 @@ var ColumnSeries = extendClass(Series, {
16396
16569
  point.graphic = graphic = renderer[point.shapeType](shapeArgs)
16397
16570
  .attr(borderAttr)
16398
16571
  .attr(pointAttr)
16399
- .add(series.group)
16572
+ .add(point.group || series.group)
16400
16573
  .shadow(options.shadow, null, options.stacking && !options.borderRadius);
16401
16574
  }
16402
16575
 
@@ -16565,10 +16738,7 @@ var PiePoint = extendClass(Point, {
16565
16738
  var point = this,
16566
16739
  toggleSlice;
16567
16740
 
16568
- extend(point, {
16569
- visible: point.visible !== false,
16570
- name: pick(point.name, 'Slice')
16571
- });
16741
+ point.name = pick(point.name, 'Slice');
16572
16742
 
16573
16743
  // add event listener for select
16574
16744
  toggleSlice = function (e) {
@@ -16725,19 +16895,6 @@ var PieSeries = {
16725
16895
  }
16726
16896
  },
16727
16897
 
16728
- /**
16729
- * Extend the basic setData method by running processData and generatePoints immediately,
16730
- * in order to access the points from the legend.
16731
- */
16732
- setData: function (data, redraw, animation, updatePoints) {
16733
- Series.prototype.setData.call(this, data, false, animation, updatePoints);
16734
- this.processData();
16735
- this.generatePoints();
16736
- if (pick(redraw, true)) {
16737
- this.chart.redraw(animation);
16738
- }
16739
- },
16740
-
16741
16898
  /**
16742
16899
  * Recompute total chart sum and update percentages of points.
16743
16900
  */
@@ -16932,7 +17089,9 @@ var PieSeries = {
16932
17089
 
16933
17090
  // draw the slice
16934
17091
  if (graphic) {
16935
- graphic.animate(extend(shapeArgs, groupTranslation));
17092
+ graphic
17093
+ .setRadialReference(series.center)
17094
+ .animate(extend(shapeArgs, groupTranslation));
16936
17095
  } else {
16937
17096
  attr = { 'stroke-linejoin': 'round' };
16938
17097
  if (!point.visible) {
@@ -17216,6 +17375,7 @@ Series.prototype.alignDataLabel = function (point, dataLabel, options, alignTo,
17216
17375
 
17217
17376
  // Show or hide based on the final aligned position
17218
17377
  if (!visible) {
17378
+ stop(dataLabel);
17219
17379
  dataLabel.attr({ y: -999 });
17220
17380
  dataLabel.placed = false; // don't animate back in
17221
17381
  }
@@ -17669,7 +17829,7 @@ if (seriesTypes.pie) {
17669
17829
  // If the size must be decreased, we need to run translate and drawDataLabels again
17670
17830
  if (newSize < center[2]) {
17671
17831
  center[2] = newSize;
17672
- center[3] = relativeLength(options.innerSize || 0, newSize);
17832
+ center[3] = Math.min(relativeLength(options.innerSize || 0, newSize), newSize); // #3632
17673
17833
  this.translate(center);
17674
17834
  each(this.points, function (point) {
17675
17835
  if (point.dataLabel) {
@@ -17745,7 +17905,7 @@ if (seriesTypes.column) {
17745
17905
 
17746
17906
 
17747
17907
  /**
17748
- * Highcharts JS v4.1.8 (2015-08-20)
17908
+ * Highcharts JS v4.1.9 (2015-10-07)
17749
17909
  * Highcharts module to hide overlapping data labels. This module is included by default in Highmaps.
17750
17910
  *
17751
17911
  * (c) 2010-2014 Torstein Honsi
@@ -18075,7 +18235,9 @@ extend(Legend.prototype, {
18075
18235
  .on('click', function (event) {
18076
18236
  var strLegendItemClick = 'legendItemClick',
18077
18237
  fnLegendItemClick = function () {
18078
- item.setVisible();
18238
+ if (item.setVisible) {
18239
+ item.setVisible();
18240
+ }
18079
18241
  };
18080
18242
 
18081
18243
  // Pass over the click/touch event. #4.
@@ -18371,7 +18533,7 @@ extend(Point.prototype, {
18371
18533
  */
18372
18534
  setState: function (state, move) {
18373
18535
  var point = this,
18374
- plotX = point.plotX,
18536
+ plotX = mathFloor(point.plotX), // #4586
18375
18537
  plotY = point.plotY,
18376
18538
  series = point.series,
18377
18539
  stateOptions = series.options.states,