highcharts-rails 4.1.8 → 4.1.9

Sign up to get free protection for your applications and to get access to all the features.
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,