highcharts-rails 5.0.7 → 5.0.8

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.
Files changed (26) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.markdown +41 -0
  3. data/README.markdown +3 -6
  4. data/app/assets/javascripts/highcharts.js +758 -455
  5. data/app/assets/javascripts/highcharts/highcharts-3d.js +58 -50
  6. data/app/assets/javascripts/highcharts/highcharts-more.js +21 -35
  7. data/app/assets/javascripts/highcharts/modules/accessibility.js +69 -39
  8. data/app/assets/javascripts/highcharts/modules/annotations.js +2 -2
  9. data/app/assets/javascripts/highcharts/modules/boost.js +2316 -337
  10. data/app/assets/javascripts/highcharts/modules/broken-axis.js +17 -3
  11. data/app/assets/javascripts/highcharts/modules/data.js +2 -2
  12. data/app/assets/javascripts/highcharts/modules/drilldown.js +6 -6
  13. data/app/assets/javascripts/highcharts/modules/exporting.js +4 -4
  14. data/app/assets/javascripts/highcharts/modules/funnel.js +4 -4
  15. data/app/assets/javascripts/highcharts/modules/grid-axis.js +6 -6
  16. data/app/assets/javascripts/highcharts/modules/heatmap.js +10 -7
  17. data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +2 -2
  18. data/app/assets/javascripts/highcharts/modules/offline-exporting.js +3 -3
  19. data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +3 -3
  20. data/app/assets/javascripts/highcharts/modules/series-label.js +2 -2
  21. data/app/assets/javascripts/highcharts/modules/solid-gauge.js +40 -4
  22. data/app/assets/javascripts/highcharts/modules/stock.js +100 -81
  23. data/app/assets/javascripts/highcharts/modules/treemap.js +36 -9
  24. data/app/assets/javascripts/highcharts/modules/xrange-series.js +2 -2
  25. data/lib/highcharts/version.rb +1 -1
  26. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 607c053da0b9fc8e51b7392df545aa6e5d297a34
4
- data.tar.gz: 2e1f5f66fe81be42f4a96afdf21ca8ad5bc12697
3
+ metadata.gz: c07fdfe881d82631125b0d41f3308e896b0b0c39
4
+ data.tar.gz: 4763f46c66ebd67f143b07553efa26b16dba9926
5
5
  SHA512:
6
- metadata.gz: abfc4475e26229dca060b337a77bf1564bfb55c66ed2d13ce8e2d156ec81811977117f3fe623a5c4bf147552a7653426c96e4e607be266ba8413e60e0af62e6c
7
- data.tar.gz: a8be44f809d4987373a16f6a2383667f066ab4c9c82b6862922e5da10ba7955ca5c1e2a3bdc6482b32c7e9cf176e970dd5b6908810ff75b5e37977b283512885
6
+ metadata.gz: 62691100992c685c381e7fc5eaf9c0c884bb1008d7aad489e4b48d5119eb72a94ef24571ada79f01b3c94c6710ac5c0b8c012f374f4e6ece510890fe0117a36d
7
+ data.tar.gz: 196d2a3665e69acb6db35981518c9694a48a761a0d97d9cd8a1bccd684f5eb8aecf84b87da1b658fca9ed4c5d1563d08e076e5b243fc4a3b96e067ca15f7cd4a
@@ -1,3 +1,44 @@
1
+ # 5.0.8 / 2017-11-10
2
+
3
+ * Updated Highcharts to 5.0.8 (2017-03-08)
4
+ * Added a refactored Boost module based on WebGL. Details and API to be announced.
5
+ * Added animation on graph mouse over and mouse out.
6
+ * Added hooks so that users can define their own log axis conversion functions, and can advertise that the log axis should allow negative values.
7
+ * Added new option, solidgauge.rounded.
8
+ * Added support for relative chart.height as a percentage of the width. This allows for fixed aspect ratio.
9
+ * Bug fixes
10
+ * Fixed #223, pie chart data labels overflowed after pie reached minimum size.
11
+ * Fixed #2322, updating series type caused remnants of the original series type after multiple updates.
12
+ * Fixed #4916, data values were lost in export after updating a point from a numeric or array configuration to an object configuration.
13
+ * Fixed #5915, returning false from tooltip formatter only hid the tooltip when it was present from before.
14
+ * Fixed #6087, minPointLength shifted next points rendering.
15
+ * Fixed #6173, another case of unwanted inline CSS in style mode.
16
+ * Fixed #6187, navigator jumped back after dragging on touch devices.
17
+ * Fixed #6254, Point.update did not apply new class names.
18
+ * Fixed #6264, enabling individual bubble markers did not work.
19
+ * Fixed #6272, inverted stack area chart was badly drawn when containing nulls.
20
+ * Fixed #6274, allowDecimals: false was ignored with flat data.
21
+ * Fixed #6278, missing ticks before DST crossover in some cases.
22
+ * Fixed #6282, text-align did not take effect on data labels with useHTML.
23
+ * Fixed #6291, multiple responsive rules were applied an unapplied in wrong order when resizing.
24
+ * Fixed #6301, legend width option caused wrong alignment when aligned right.
25
+ * Fixed #6305, accessible keyboard navigation in polar charts not working correctly.
26
+ * Fixed #6314, treemap series failed with error in styled mode.
27
+ * Fixed #6321, bubbles were hidden when close and marker.enabled set to null.
28
+ * Fixed #6322, legend navigation arrows did not update correctly on responsiveness.
29
+ * Fixed #6328, issue with disabled tooltip in accessibility module.
30
+ * Fixed #6330, minor ticks affecting the computed extremes of Y axes in some cases.
31
+ * Fixed #6330, minor ticks were not applied outside major ticks on a logarithmic axis.
32
+ * Fixed #6347, error on applying responsive rules where series or axis length was greater than the existing chart.
33
+ * Fixed #6356, legend.maxHeight not respected after chart update.
34
+ * Fixed #6361, accessibility failing for IE8 and older.
35
+ * Fixed #6370, category axis with breaks was rendered incorrectly.
36
+ * Fixed #6384, Point.update didn't work with slice: false.
37
+ * Fixed #6387, graph and area rendered differently on area splines next to null points.
38
+ * Fixed #6399, treemap legend item had incorrect color after point was hidden.
39
+ * Fixed #6401, point.states didn't work for maps.
40
+ * Fixed #6402, treemap ignoreHiddenPoint is now true by default.
41
+
1
42
  # 5.0.7 / 2017-01-25
2
43
 
3
44
  * Updated Highcharts to 5.0.7 (2017-01-17)
@@ -26,14 +26,9 @@ In your JavaScript manifest (e.g. `application.js`)
26
26
  // to get the new features in 2.3.0:
27
27
  //= require highcharts/highcharts-more
28
28
 
29
- To include one of the other adapters
30
-
31
- //= require highcharts/adapters/standalone-framework
32
-
33
- Or the modules
29
+ Including the modules you want and need
34
30
 
35
31
  //= require highcharts/modules/annotations
36
- //= require highcharts/modules/canvas-tools
37
32
  //= require highcharts/modules/data
38
33
  //= require highcharts/modules/drilldown
39
34
  //= require highcharts/modules/exporting
@@ -50,6 +45,8 @@ Or one of the themes
50
45
  //= require highcharts/themes/grid
51
46
  //= require highcharts/themes/skies
52
47
 
48
+ Some of the modules are meant to be loaded by Highcharts on-demand, such as `canvas-tools` (https://github.com/highcharts/highcharts/issues/2311#issuecomment-25685317), so don't require them on your own.
49
+
53
50
  Other than that, refer to the [Highcharts documentation](http://www.highcharts.com/docs)
54
51
 
55
52
  ## Licensing
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.7 (2017-01-17)
2
+ * @license Highcharts JS v5.0.8 (2017-03-08)
3
3
  *
4
4
  * (c) 2009-2016 Torstein Honsi
5
5
  *
@@ -21,7 +21,6 @@
21
21
  *
22
22
  * License: www.highcharts.com/license
23
23
  */
24
- 'use strict';
25
24
  /* global window */
26
25
  var win = window,
27
26
  doc = win.document;
@@ -36,7 +35,7 @@
36
35
 
37
36
  var Highcharts = win.Highcharts ? win.Highcharts.error(16, true) : {
38
37
  product: 'Highcharts',
39
- version: '5.0.7',
38
+ version: '5.0.8',
40
39
  deg2rad: Math.PI * 2 / 360,
41
40
  doc: doc,
42
41
  hasBidiBug: hasBidiBug,
@@ -67,7 +66,6 @@
67
66
  * License: www.highcharts.com/license
68
67
  */
69
68
  /* eslint max-len: ["warn", 80, 4] */
70
- 'use strict';
71
69
 
72
70
  /**
73
71
  * The Highcharts object is the placeholder for all other members, and various
@@ -1597,9 +1595,10 @@
1597
1595
  * @function #each
1598
1596
  * @memberOf Highcharts
1599
1597
  * @param {Array} arr - The array to iterate over.
1600
- * @param {Function} fn - The iterator callback. It passes two arguments:
1598
+ * @param {Function} fn - The iterator callback. It passes three arguments:
1601
1599
  * * item - The array item.
1602
1600
  * * index - The item's index in the array.
1601
+ * * arr - The array that each is being applied to.
1603
1602
  * @param {Object} [ctx] The context.
1604
1603
  */
1605
1604
  H.each = function(arr, fn, ctx) { // modern browsers
@@ -1890,7 +1889,7 @@
1890
1889
  if (!end) {
1891
1890
  end = params[prop];
1892
1891
  }
1893
- if (end.match && end.match('px')) {
1892
+ if (end && end.match && end.match('px')) {
1894
1893
  end = end.replace(/px/g, ''); // #4351
1895
1894
  }
1896
1895
  fx.run(start, end, unit);
@@ -2096,7 +2095,6 @@
2096
2095
  *
2097
2096
  * License: www.highcharts.com/license
2098
2097
  */
2099
- 'use strict';
2100
2098
  var each = H.each,
2101
2099
  isNumber = H.isNumber,
2102
2100
  map = H.map,
@@ -2133,12 +2131,6 @@
2133
2131
  parse: function(result) {
2134
2132
  return [pInt(result[1]), pInt(result[2]), pInt(result[3]), parseFloat(result[4], 10)];
2135
2133
  }
2136
- }, {
2137
- // HEX color
2138
- regex: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/,
2139
- parse: function(result) {
2140
- return [pInt(result[1], 16), pInt(result[2], 16), pInt(result[3], 16), 1];
2141
- }
2142
2134
  }, {
2143
2135
  // RGB color
2144
2136
  regex: /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/,
@@ -2162,7 +2154,8 @@
2162
2154
  var result,
2163
2155
  rgba,
2164
2156
  i,
2165
- parser;
2157
+ parser,
2158
+ len;
2166
2159
 
2167
2160
  this.input = input = this.names[input] || input;
2168
2161
 
@@ -2174,12 +2167,46 @@
2174
2167
 
2175
2168
  // Solid colors
2176
2169
  } else {
2177
- i = this.parsers.length;
2178
- while (i-- && !rgba) {
2179
- parser = this.parsers[i];
2180
- result = parser.regex.exec(input);
2181
- if (result) {
2182
- rgba = parser.parse(result);
2170
+
2171
+ // Check if it's possible to do bitmasking instead of regex
2172
+ if (input && input[0] === '#') {
2173
+
2174
+ len = input.length;
2175
+ input = parseInt(input.substr(1), 16);
2176
+
2177
+ // Handle long-form, e.g. #AABBCC
2178
+ if (len === 7) {
2179
+
2180
+ rgba = [
2181
+ (input & 0xFF0000) >> 16,
2182
+ (input & 0xFF00) >> 8,
2183
+ (input & 0xFF),
2184
+ 1
2185
+ ];
2186
+
2187
+ // Handle short-form, e.g. #ABC
2188
+ // In short form, the value is assumed to be the same
2189
+ // for both nibbles for each component. e.g. #ABC = #AABBCC
2190
+ } else if (len === 4) {
2191
+
2192
+ rgba = [
2193
+ ((input & 0xF00) >> 4) | (input & 0xF00) >> 8,
2194
+ ((input & 0xF0) >> 4) | (input & 0xF0),
2195
+ ((input & 0xF) << 4) | (input & 0xF),
2196
+ 1
2197
+ ];
2198
+ }
2199
+ }
2200
+
2201
+ // Otherwise, check regex parsers
2202
+ if (!rgba) {
2203
+ i = this.parsers.length;
2204
+ while (i-- && !rgba) {
2205
+ parser = this.parsers[i];
2206
+ result = parser.regex.exec(input);
2207
+ if (result) {
2208
+ rgba = parser.parse(result);
2209
+ }
2183
2210
  }
2184
2211
  }
2185
2212
  }
@@ -2265,7 +2292,6 @@
2265
2292
  *
2266
2293
  * License: www.highcharts.com/license
2267
2294
  */
2268
- 'use strict';
2269
2295
  var SVGElement,
2270
2296
  SVGRenderer,
2271
2297
 
@@ -2336,8 +2362,8 @@
2336
2362
  * @type {Array.<string>}
2337
2363
  */
2338
2364
  textProps: ['direction', 'fontSize', 'fontWeight', 'fontFamily',
2339
- 'fontStyle', 'color', 'lineHeight', 'width', 'textDecoration',
2340
- 'textOverflow', 'textOutline'
2365
+ 'fontStyle', 'color', 'lineHeight', 'width', 'textAlign',
2366
+ 'textDecoration', 'textOverflow', 'textOutline'
2341
2367
  ],
2342
2368
 
2343
2369
  /**
@@ -2385,6 +2411,9 @@
2385
2411
  animate(this, params, animOptions);
2386
2412
  } else {
2387
2413
  this.attr(params, null, complete);
2414
+ if (animOptions.step) {
2415
+ animOptions.step.call(this);
2416
+ }
2388
2417
  }
2389
2418
  return this;
2390
2419
  },
@@ -2946,10 +2975,9 @@
2946
2975
  * @returns {SVGElement} Return the SVG element for chaining.
2947
2976
  */
2948
2977
  css: function(styles) {
2949
- var elemWrapper = this,
2950
- oldStyles = elemWrapper.styles,
2978
+ var oldStyles = this.styles,
2951
2979
  newStyles = {},
2952
- elem = elemWrapper.element,
2980
+ elem = this.element,
2953
2981
  textWidth,
2954
2982
  n,
2955
2983
  serializedCss = '',
@@ -2976,9 +3004,6 @@
2976
3004
  }
2977
3005
  }
2978
3006
  if (hasNew) {
2979
- textWidth = elemWrapper.textWidth =
2980
- (styles && styles.width && elem.nodeName.toLowerCase() === 'text' && pInt(styles.width)) ||
2981
- elemWrapper.textWidth; // #3501
2982
3007
 
2983
3008
  // Merge the new styles with the old ones
2984
3009
  if (oldStyles) {
@@ -2988,16 +3013,25 @@
2988
3013
  );
2989
3014
  }
2990
3015
 
3016
+ // Get the text width from style
3017
+ textWidth = this.textWidth = (
3018
+ styles &&
3019
+ styles.width &&
3020
+ styles.width !== 'auto' &&
3021
+ elem.nodeName.toLowerCase() === 'text' &&
3022
+ pInt(styles.width)
3023
+ );
3024
+
2991
3025
  // store object
2992
- elemWrapper.styles = styles;
3026
+ this.styles = styles;
2993
3027
 
2994
- if (textWidth && (!svg && elemWrapper.renderer.forExport)) {
3028
+ if (textWidth && (!svg && this.renderer.forExport)) {
2995
3029
  delete styles.width;
2996
3030
  }
2997
3031
 
2998
3032
  // serialize and set style attribute
2999
3033
  if (isMS && !svg) {
3000
- css(elemWrapper.element, styles);
3034
+ css(this.element, styles);
3001
3035
  } else {
3002
3036
  hyphenate = function(a, b) {
3003
3037
  return '-' + b.toLowerCase();
@@ -3015,20 +3049,22 @@
3015
3049
  }
3016
3050
 
3017
3051
 
3018
- if (elemWrapper.added) {
3019
- // Rebuild text after added
3020
- if (textWidth) {
3021
- elemWrapper.renderer.buildText(elemWrapper);
3052
+ if (this.added) {
3053
+
3054
+ // Rebuild text after added. Cache mechanisms in the buildText
3055
+ // will prevent building if there are no significant changes.
3056
+ if (this.element.nodeName === 'text') {
3057
+ this.renderer.buildText(this);
3022
3058
  }
3023
3059
 
3024
3060
  // Apply text outline after added
3025
3061
  if (styles && styles.textOutline) {
3026
- elemWrapper.applyTextOutline(styles.textOutline);
3062
+ this.applyTextOutline(styles.textOutline);
3027
3063
  }
3028
3064
  }
3029
3065
  }
3030
3066
 
3031
- return elemWrapper;
3067
+ return this;
3032
3068
  },
3033
3069
 
3034
3070
 
@@ -3986,7 +4022,7 @@
3986
4022
  'class': 'highcharts-root'
3987
4023
  })
3988
4024
 
3989
- .css(this.getStyle(style));
4025
+ .css(this.getStyle(style));
3990
4026
  element = boxWrapper.element;
3991
4027
  container.appendChild(element);
3992
4028
 
@@ -4025,7 +4061,7 @@
4025
4061
 
4026
4062
  // Add description
4027
4063
  desc = this.createElement('desc').add();
4028
- desc.element.appendChild(doc.createTextNode('Created with Highcharts 5.0.7'));
4064
+ desc.element.appendChild(doc.createTextNode('Created with Highcharts 5.0.8'));
4029
4065
 
4030
4066
 
4031
4067
  renderer.defs = this.createElement('defs').add();
@@ -4262,8 +4298,10 @@
4262
4298
 
4263
4299
  if (hasMarkup) {
4264
4300
  lines = textStr
4301
+
4265
4302
  .replace(/<(b|strong)>/g, '<span style="font-weight:bold">')
4266
4303
  .replace(/<(i|em)>/g, '<span style="font-style:italic">')
4304
+
4267
4305
  .replace(/<a/g, '<span')
4268
4306
  .replace(/<\/(b|strong|i|em|a)>/g, '</span>')
4269
4307
  .split(/<br.*?>/g);
@@ -4723,24 +4761,28 @@
4723
4761
  * @returns {SVGElement} The generated wrapper element.
4724
4762
  */
4725
4763
  arc: function(x, y, r, innerR, start, end) {
4726
- var arc;
4764
+ var arc,
4765
+ options;
4727
4766
 
4728
4767
  if (isObject(x)) {
4729
- y = x.y;
4730
- r = x.r;
4731
- innerR = x.innerR;
4732
- start = x.start;
4733
- end = x.end;
4734
- x = x.x;
4768
+ options = x;
4769
+ y = options.y;
4770
+ r = options.r;
4771
+ innerR = options.innerR;
4772
+ start = options.start;
4773
+ end = options.end;
4774
+ x = options.x;
4775
+ } else {
4776
+ options = {
4777
+ innerR: innerR,
4778
+ start: start,
4779
+ end: end
4780
+ };
4735
4781
  }
4736
4782
 
4737
4783
  // Arcs are defined as symbols for the ability to set
4738
4784
  // attributes in attr and animate
4739
- arc = this.symbol('arc', x || 0, y || 0, r || 0, r || 0, {
4740
- innerR: innerR || 0,
4741
- start: start || 0,
4742
- end: end || 0
4743
- });
4785
+ arc = this.symbol('arc', x, y, r, r, options);
4744
4786
  arc.r = r; // #959
4745
4787
  return arc;
4746
4788
  },
@@ -5596,7 +5638,7 @@
5596
5638
 
5597
5639
  // only change local variables
5598
5640
  wrapper.widthSetter = function(value) {
5599
- width = value;
5641
+ width = H.isNumber(value) ? value : null; // width:auto => null
5600
5642
  };
5601
5643
  wrapper.heightSetter = function(value) {
5602
5644
  height = value;
@@ -5769,7 +5811,6 @@
5769
5811
  *
5770
5812
  * License: www.highcharts.com/license
5771
5813
  */
5772
- 'use strict';
5773
5814
  var attr = H.attr,
5774
5815
  createElement = H.createElement,
5775
5816
  css = H.css,
@@ -6132,7 +6173,6 @@
6132
6173
  *
6133
6174
  * License: www.highcharts.com/license
6134
6175
  */
6135
- 'use strict';
6136
6176
 
6137
6177
  var VMLRenderer,
6138
6178
  VMLRendererExtension,
@@ -7284,7 +7324,6 @@
7284
7324
  *
7285
7325
  * License: www.highcharts.com/license
7286
7326
  */
7287
- 'use strict';
7288
7327
  var color = H.color,
7289
7328
  each = H.each,
7290
7329
  getTZOffset = H.getTZOffset,
@@ -7327,7 +7366,7 @@
7327
7366
  useUTC: true,
7328
7367
  //timezoneOffset: 0,
7329
7368
 
7330
- VMLRadialGradientURL: 'http://code.highcharts.com/5.0.7/gfx/vml-radial-gradient.png'
7369
+ VMLRadialGradientURL: 'http://code.highcharts.com/5.0.8/gfx/vml-radial-gradient.png'
7331
7370
 
7332
7371
  },
7333
7372
  chart: {
@@ -7377,8 +7416,8 @@
7377
7416
  backgroundColor: '#ffffff',
7378
7417
  //plotBackgroundColor: null,
7379
7418
  plotBorderColor: '#cccccc'
7380
- //plotBorderWidth: 0,
7381
- //plotShadow: false
7419
+ //plotBorderWidth: 0,
7420
+ //plotShadow: false
7382
7421
 
7383
7422
  },
7384
7423
  title: {
@@ -7673,7 +7712,6 @@
7673
7712
  *
7674
7713
  * License: www.highcharts.com/license
7675
7714
  */
7676
- 'use strict';
7677
7715
  var arrayMax = H.arrayMax,
7678
7716
  arrayMin = H.arrayMin,
7679
7717
  defined = H.defined,
@@ -8000,7 +8038,6 @@
8000
8038
  *
8001
8039
  * License: www.highcharts.com/license
8002
8040
  */
8003
- 'use strict';
8004
8041
  var correctFloat = H.correctFloat,
8005
8042
  defined = H.defined,
8006
8043
  destroyObjectProperties = H.destroyObjectProperties,
@@ -8084,10 +8121,10 @@
8084
8121
  labelOptions.useHTML
8085
8122
  )
8086
8123
 
8087
- // without position absolute, IE export sometimes is wrong
8088
- .css(merge(labelOptions.style))
8124
+ // without position absolute, IE export sometimes is wrong
8125
+ .css(merge(labelOptions.style))
8089
8126
 
8090
- .add(axis.labelGroup):
8127
+ .add(axis.labelGroup) :
8091
8128
  null;
8092
8129
  tick.labelLength = label && label.getBBox().width; // Un-rotated length
8093
8130
  tick.rotation = 0; // Base value to detect change for new calls to getBBox
@@ -8261,51 +8298,31 @@
8261
8298
  },
8262
8299
 
8263
8300
  /**
8264
- * Put everything in place
8265
- *
8266
- * @param index {Number}
8267
- * @param old {Boolean} Use old coordinates to prepare an animation into new position
8301
+ * Renders the gridLine.
8302
+ * @param {Boolean} old Whether or not the tick is old
8303
+ * @param {number} opacity The opacity of the grid line
8304
+ * @param {number} reverseCrisp Modifier for avoiding overlapping 1 or -1
8305
+ * @return {undefined}
8268
8306
  */
8269
- render: function(index, old, opacity) {
8307
+ renderGridLine: function(old, opacity, reverseCrisp) {
8270
8308
  var tick = this,
8271
8309
  axis = tick.axis,
8272
8310
  options = axis.options,
8273
- chart = axis.chart,
8274
- renderer = chart.renderer,
8275
- horiz = axis.horiz,
8276
- type = tick.type,
8277
- label = tick.label,
8278
- pos = tick.pos,
8279
- labelOptions = options.labels,
8280
8311
  gridLine = tick.gridLine,
8281
- tickPrefix = type ? type + 'Tick' : 'tick',
8282
- tickSize = axis.tickSize(tickPrefix),
8283
8312
  gridLinePath,
8284
- mark = tick.mark,
8285
- isNewMark = !mark,
8286
- step = labelOptions.step,
8287
8313
  attribs = {},
8288
- show = true,
8314
+ pos = tick.pos,
8315
+ type = tick.type,
8289
8316
  tickmarkOffset = axis.tickmarkOffset,
8290
- xy = tick.getPosition(horiz, pos, tickmarkOffset, old),
8291
- x = xy.x,
8292
- y = xy.y,
8293
- reverseCrisp = ((horiz && x === axis.pos + axis.len) ||
8294
- (!horiz && y === axis.pos)) ? -1 : 1; // #1480, #1687
8317
+ renderer = axis.chart.renderer;
8295
8318
 
8296
8319
 
8297
8320
  var gridPrefix = type ? type + 'Grid' : 'grid',
8298
8321
  gridLineWidth = options[gridPrefix + 'LineWidth'],
8299
8322
  gridLineColor = options[gridPrefix + 'LineColor'],
8300
- dashStyle = options[gridPrefix + 'LineDashStyle'],
8301
- tickWidth = pick(options[tickPrefix + 'Width'], !type && axis.isXAxis ? 1 : 0), // X axis defaults to 1
8302
- tickColor = options[tickPrefix + 'Color'];
8303
-
8323
+ dashStyle = options[gridPrefix + 'LineDashStyle'];
8304
8324
 
8305
- opacity = pick(opacity, 1);
8306
- this.isActive = true;
8307
8325
 
8308
- // Create the grid line
8309
8326
  if (!gridLine) {
8310
8327
 
8311
8328
  attribs.stroke = gridLineColor;
@@ -8322,14 +8339,20 @@
8322
8339
  }
8323
8340
  tick.gridLine = gridLine = renderer.path()
8324
8341
  .attr(attribs)
8325
- .addClass('highcharts-' + (type ? type + '-' : '') + 'grid-line')
8342
+ .addClass(
8343
+ 'highcharts-' + (type ? type + '-' : '') + 'grid-line'
8344
+ )
8326
8345
  .add(axis.gridGroup);
8327
8346
  }
8328
8347
 
8329
8348
  // If the parameter 'old' is set, the current call will be followed
8330
8349
  // by another call, therefore do not do any animations this time
8331
8350
  if (!old && gridLine) {
8332
- gridLinePath = axis.getPlotLinePath(pos + tickmarkOffset, gridLine.strokeWidth() * reverseCrisp, old, true);
8351
+ gridLinePath = axis.getPlotLinePath(
8352
+ pos + tickmarkOffset,
8353
+ gridLine.strokeWidth() * reverseCrisp,
8354
+ old, true
8355
+ );
8333
8356
  if (gridLinePath) {
8334
8357
  gridLine[tick.isNew ? 'attr' : 'animate']({
8335
8358
  d: gridLinePath,
@@ -8337,8 +8360,37 @@
8337
8360
  });
8338
8361
  }
8339
8362
  }
8363
+ },
8364
+
8365
+ /**
8366
+ * Renders the tick mark.
8367
+ * @param {Object} xy The position vector of the mark
8368
+ * @param {number} xy.x The x position of the mark
8369
+ * @param {number} xy.y The y position of the mark
8370
+ * @param {number} opacity The opacity of the mark
8371
+ * @param {number} reverseCrisp Modifier for avoiding overlapping 1 or -1
8372
+ * @return {undefined}
8373
+ */
8374
+ renderMark: function(xy, opacity, reverseCrisp) {
8375
+ var tick = this,
8376
+ axis = tick.axis,
8377
+ options = axis.options,
8378
+ renderer = axis.chart.renderer,
8379
+ type = tick.type,
8380
+ tickPrefix = type ? type + 'Tick' : 'tick',
8381
+ tickSize = axis.tickSize(tickPrefix),
8382
+ mark = tick.mark,
8383
+ isNewMark = !mark,
8384
+ x = xy.x,
8385
+ y = xy.y;
8386
+
8387
+
8388
+ var tickWidth = pick(
8389
+ options[tickPrefix + 'Width'], !type && axis.isXAxis ? 1 : 0
8390
+ ), // X axis defaults to 1
8391
+ tickColor = options[tickPrefix + 'Color'];
8392
+
8340
8393
 
8341
- // create the tick mark
8342
8394
  if (tickSize) {
8343
8395
 
8344
8396
  // negate the length
@@ -8360,20 +8412,70 @@
8360
8412
 
8361
8413
  }
8362
8414
  mark[isNewMark ? 'attr' : 'animate']({
8363
- d: tick.getMarkPath(x, y, tickSize[0], mark.strokeWidth() * reverseCrisp, horiz, renderer),
8415
+ d: tick.getMarkPath(
8416
+ x,
8417
+ y,
8418
+ tickSize[0],
8419
+ mark.strokeWidth() * reverseCrisp,
8420
+ axis.horiz,
8421
+ renderer),
8364
8422
  opacity: opacity
8365
8423
  });
8366
8424
 
8367
8425
  }
8426
+ },
8368
8427
 
8369
- // the label is created on init - now move it into place
8428
+ /**
8429
+ * Renders the tick label.
8430
+ * Note: The label should already be created in init(), so it should only
8431
+ * have to be moved into place.
8432
+ * @param {Object} xy The position vector of the label
8433
+ * @param {number} xy.x The x position of the label
8434
+ * @param {number} xy.y The y position of the label
8435
+ * @param {Boolean} old Whether or not the tick is old
8436
+ * @param {number} opacity The opacity of the label
8437
+ * @param {number} index The index of the tick
8438
+ * @return {undefined}
8439
+ */
8440
+ renderLabel: function(xy, old, opacity, index) {
8441
+ var tick = this,
8442
+ axis = tick.axis,
8443
+ horiz = axis.horiz,
8444
+ options = axis.options,
8445
+ label = tick.label,
8446
+ labelOptions = options.labels,
8447
+ step = labelOptions.step,
8448
+ tickmarkOffset = axis.tickmarkOffset,
8449
+ show = true,
8450
+ x = xy.x,
8451
+ y = xy.y;
8370
8452
  if (label && isNumber(x)) {
8371
- label.xy = xy = tick.getLabelPosition(x, y, label, horiz, labelOptions, tickmarkOffset, index, step);
8453
+ label.xy = xy = tick.getLabelPosition(
8454
+ x,
8455
+ y,
8456
+ label,
8457
+ horiz,
8458
+ labelOptions,
8459
+ tickmarkOffset,
8460
+ index,
8461
+ step
8462
+ );
8372
8463
 
8373
- // Apply show first and show last. If the tick is both first and last, it is
8374
- // a single centered tick, in which case we show the label anyway (#2100).
8375
- if ((tick.isFirst && !tick.isLast && !pick(options.showFirstLabel, 1)) ||
8376
- (tick.isLast && !tick.isFirst && !pick(options.showLastLabel, 1))) {
8464
+ // Apply show first and show last. If the tick is both first and
8465
+ // last, it is a single centered tick, in which case we show the
8466
+ // label anyway (#2100).
8467
+ if (
8468
+ (
8469
+ tick.isFirst &&
8470
+ !tick.isLast &&
8471
+ !pick(options.showFirstLabel, 1)
8472
+ ) ||
8473
+ (
8474
+ tick.isLast &&
8475
+ !tick.isFirst &&
8476
+ !pick(options.showLastLabel, 1)
8477
+ )
8478
+ ) {
8377
8479
  show = false;
8378
8480
 
8379
8481
  // Handle label overflow and show or hide accordingly
@@ -8399,6 +8501,38 @@
8399
8501
  }
8400
8502
  },
8401
8503
 
8504
+ /**
8505
+ * Put everything in place
8506
+ *
8507
+ * @param index {Number}
8508
+ * @param old {Boolean} Use old coordinates to prepare an animation into new
8509
+ * position
8510
+ */
8511
+ render: function(index, old, opacity) {
8512
+ var tick = this,
8513
+ axis = tick.axis,
8514
+ horiz = axis.horiz,
8515
+ pos = tick.pos,
8516
+ tickmarkOffset = axis.tickmarkOffset,
8517
+ xy = tick.getPosition(horiz, pos, tickmarkOffset, old),
8518
+ x = xy.x,
8519
+ y = xy.y,
8520
+ reverseCrisp = ((horiz && x === axis.pos + axis.len) ||
8521
+ (!horiz && y === axis.pos)) ? -1 : 1; // #1480, #1687
8522
+
8523
+ opacity = pick(opacity, 1);
8524
+ this.isActive = true;
8525
+
8526
+ // Create the grid line
8527
+ this.renderGridLine(old, opacity, reverseCrisp);
8528
+
8529
+ // create the tick mark
8530
+ this.renderMark(xy, opacity, reverseCrisp);
8531
+
8532
+ // the label is created on init - now move it into place
8533
+ this.renderLabel(xy, old, opacity, index);
8534
+ },
8535
+
8402
8536
  /**
8403
8537
  * Destructor for the tick prototype
8404
8538
  */
@@ -8414,7 +8548,6 @@
8414
8548
  *
8415
8549
  * License: www.highcharts.com/license
8416
8550
  */
8417
- 'use strict';
8418
8551
 
8419
8552
  var addEvent = H.addEvent,
8420
8553
  animObject = H.animObject,
@@ -8491,10 +8624,10 @@
8491
8624
  },
8492
8625
 
8493
8626
  x: 0
8494
- //y: undefined
8495
- /*formatter: function () {
8496
- return this.value;
8497
- },*/
8627
+ //y: undefined
8628
+ /*formatter: function () {
8629
+ return this.value;
8630
+ },*/
8498
8631
  },
8499
8632
  //linkedTo: null,
8500
8633
  //max: undefined,
@@ -8556,7 +8689,7 @@
8556
8689
  // gridLineDashStyle: 'solid',
8557
8690
  // gridLineWidth: 0,
8558
8691
  tickColor: '#ccd6eb'
8559
- // tickWidth: 1
8692
+ // tickWidth: 1
8560
8693
 
8561
8694
  },
8562
8695
 
@@ -8600,7 +8733,7 @@
8600
8733
 
8601
8734
  gridLineWidth: 1,
8602
8735
  lineWidth: 0
8603
- // tickWidth: 0
8736
+ // tickWidth: 0
8604
8737
 
8605
8738
  },
8606
8739
 
@@ -8635,8 +8768,8 @@
8635
8768
  labels: {
8636
8769
  autoRotation: [-45],
8637
8770
  x: 0
8638
- // overflow: undefined,
8639
- // staggerLines: null
8771
+ // overflow: undefined,
8772
+ // staggerLines: null
8640
8773
  },
8641
8774
  title: {
8642
8775
  rotation: 0
@@ -8649,8 +8782,8 @@
8649
8782
  labels: {
8650
8783
  autoRotation: [-45],
8651
8784
  x: 0
8652
- // overflow: undefined
8653
- // staggerLines: null
8785
+ // overflow: undefined
8786
+ // staggerLines: null
8654
8787
  },
8655
8788
  title: {
8656
8789
  rotation: 0
@@ -8714,6 +8847,7 @@
8714
8847
  // Shorthand types
8715
8848
  axis.isLog = type === 'logarithmic';
8716
8849
  axis.isDatetimeAxis = isDatetimeAxis;
8850
+ axis.positiveValuesOnly = axis.isLog && !axis.allowNegativeLog;
8717
8851
 
8718
8852
  // Flag, if axis is linked to another axis
8719
8853
  axis.isLinked = defined(options.linkedTo);
@@ -8812,6 +8946,7 @@
8812
8946
  }
8813
8947
 
8814
8948
  // extend logarithmic axis
8949
+ axis.lin2log = options.linearToLogConverter || axis.lin2log;
8815
8950
  if (axis.isLog) {
8816
8951
  axis.val2lin = axis.log2lin;
8817
8952
  axis.lin2val = axis.lin2log;
@@ -8851,7 +8986,7 @@
8851
8986
  formatOption = axis.options.labels.format,
8852
8987
 
8853
8988
  // make sure the same symbol is added for all labels on a linear axis
8854
- numericSymbolDetector = axis.isLog ? value : axis.tickInterval;
8989
+ numericSymbolDetector = axis.isLog ? Math.abs(value) : axis.tickInterval;
8855
8990
 
8856
8991
  if (formatOption) {
8857
8992
  ret = format(formatOption, this);
@@ -8915,7 +9050,7 @@
8915
9050
  axis.hasVisibleSeries = true;
8916
9051
 
8917
9052
  // Validate threshold in logarithmic axes
8918
- if (axis.isLog && threshold <= 0) {
9053
+ if (axis.positiveValuesOnly && threshold <= 0) {
8919
9054
  threshold = null;
8920
9055
  }
8921
9056
 
@@ -8960,7 +9095,7 @@
8960
9095
  axis.threshold = threshold;
8961
9096
  }
8962
9097
  // If any series has a hard threshold, it takes precedence
8963
- if (!seriesOptions.softThreshold || axis.isLog) {
9098
+ if (!seriesOptions.softThreshold || axis.positiveValuesOnly) {
8964
9099
  axis.softThreshold = false;
8965
9100
  }
8966
9101
  }
@@ -9107,8 +9242,9 @@
9107
9242
  roundedMax = correctFloat(Math.ceil(max / tickInterval) * tickInterval),
9108
9243
  tickPositions = [];
9109
9244
 
9110
- // For single points, add a tick regardless of the relative position (#2662)
9111
- if (min === max && isNumber(min)) {
9245
+ // For single points, add a tick regardless of the relative position
9246
+ // (#2662, #6274)
9247
+ if (this.single) {
9112
9248
  return [min];
9113
9249
  }
9114
9250
 
@@ -9145,23 +9281,31 @@
9145
9281
  minorTickInterval = axis.minorTickInterval,
9146
9282
  minorTickPositions = [],
9147
9283
  pos,
9148
- i,
9149
9284
  pointRangePadding = axis.pointRangePadding || 0,
9150
9285
  min = axis.min - pointRangePadding, // #1498
9151
9286
  max = axis.max + pointRangePadding, // #1498
9152
- range = max - min,
9153
- len;
9287
+ range = max - min;
9154
9288
 
9155
9289
  // If minor ticks get too dense, they are hard to read, and may cause long running script. So we don't draw them.
9156
9290
  if (range && range / minorTickInterval < axis.len / 3) { // #3875
9157
9291
 
9158
9292
  if (axis.isLog) {
9159
- len = tickPositions.length;
9160
- for (i = 1; i < len; i++) {
9161
- minorTickPositions = minorTickPositions.concat(
9162
- axis.getLogTickPositions(minorTickInterval, tickPositions[i - 1], tickPositions[i], true)
9163
- );
9164
- }
9293
+ // For each interval in the major ticks, compute the minor ticks
9294
+ // separately.
9295
+ each(this.paddedTicks, function(pos, i, paddedTicks) {
9296
+ if (i) {
9297
+ minorTickPositions.push.apply(
9298
+ minorTickPositions,
9299
+ axis.getLogTickPositions(
9300
+ minorTickInterval,
9301
+ paddedTicks[i - 1],
9302
+ paddedTicks[i],
9303
+ true
9304
+ )
9305
+ );
9306
+ }
9307
+ });
9308
+
9165
9309
  } else if (axis.isDatetimeAxis && options.minorTickInterval === 'auto') { // #1314
9166
9310
  minorTickPositions = minorTickPositions.concat(
9167
9311
  axis.getTimeTicks(
@@ -9184,8 +9328,8 @@
9184
9328
  }
9185
9329
  }
9186
9330
 
9187
- if (minorTickPositions.length !== 0) { // don't change the extremes, when there is no minor ticks
9188
- axis.trimTicks(minorTickPositions, options.startOnTick, options.endOnTick); // #3652 #3743 #1498
9331
+ if (minorTickPositions.length !== 0) {
9332
+ axis.trimTicks(minorTickPositions); // #3652 #3743 #1498 #6330
9189
9333
  }
9190
9334
  return minorTickPositions;
9191
9335
  },
@@ -9435,7 +9579,9 @@
9435
9579
  if (saveOld) {
9436
9580
  axis.oldTransA = transA;
9437
9581
  }
9438
- axis.translationSlope = axis.transA = transA = axis.len / ((range + pointRangePadding) || 1);
9582
+ axis.translationSlope = axis.transA = transA =
9583
+ axis.options.staticScale ||
9584
+ axis.len / ((range + pointRangePadding) || 1);
9439
9585
  axis.transB = axis.horiz ? axis.left : axis.bottom; // translation addend
9440
9586
  axis.minPixelPadding = transA * minPointOffset;
9441
9587
  },
@@ -9510,7 +9656,11 @@
9510
9656
  }
9511
9657
 
9512
9658
  if (isLog) {
9513
- if (!secondPass && Math.min(axis.min, pick(axis.dataMin, axis.min)) <= 0) { // #978
9659
+ if (
9660
+ axis.positiveValuesOnly &&
9661
+ !secondPass &&
9662
+ Math.min(axis.min, pick(axis.dataMin, axis.min)) <= 0
9663
+ ) { // #978
9514
9664
  H.error(10, 1); // Can't plot negative values on log axis
9515
9665
  }
9516
9666
  // The correctFloat cures #934, float errors on full tens. But it
@@ -9659,8 +9809,7 @@
9659
9809
  tickPositionsOption = options.tickPositions,
9660
9810
  tickPositioner = options.tickPositioner,
9661
9811
  startOnTick = options.startOnTick,
9662
- endOnTick = options.endOnTick,
9663
- single;
9812
+ endOnTick = options.endOnTick;
9664
9813
 
9665
9814
  // Set the tickmarkOffset
9666
9815
  this.tickmarkOffset = (this.categories && options.tickmarkPlacement === 'between' &&
@@ -9671,6 +9820,13 @@
9671
9820
  this.minorTickInterval = options.minorTickInterval === 'auto' && this.tickInterval ?
9672
9821
  this.tickInterval / 5 : options.minorTickInterval;
9673
9822
 
9823
+ // When there is only one point, or all points have the same value on
9824
+ // this axis, then min and max are equal and tickPositions.length is 0
9825
+ // or 1. In this case, add some padding in order to center the point,
9826
+ // but leave it with one tick. #1337.
9827
+ this.single = this.min === this.max && defined(this.min) &&
9828
+ !this.tickAmount && options.allowDecimals !== false;
9829
+
9674
9830
  // Find the tick positions
9675
9831
  this.tickPositions = tickPositions = tickPositionsOption && tickPositionsOption.slice(); // Work on a copy (#1565)
9676
9832
  if (!tickPositions) {
@@ -9708,19 +9864,16 @@
9708
9864
 
9709
9865
  }
9710
9866
 
9711
- // reset min/max or remove extremes based on start/end on tick
9867
+ // Reset min/max or remove extremes based on start/end on tick
9868
+ this.paddedTicks = tickPositions.slice(0); // Used for logarithmic minor
9712
9869
  this.trimTicks(tickPositions, startOnTick, endOnTick);
9713
9870
  if (!this.isLinked) {
9714
- // When there is only one point, or all points have the same value on this axis, then min
9715
- // and max are equal and tickPositions.length is 0 or 1. In this case, add some padding
9716
- // in order to center the point, but leave it with one tick. #1337.
9717
- if (this.min === this.max && defined(this.min) && !this.tickAmount) {
9718
- // Substract half a unit (#2619, #2846, #2515, #3390)
9719
- single = true;
9871
+
9872
+ // Substract half a unit (#2619, #2846, #2515, #3390)
9873
+ if (this.single) {
9720
9874
  this.min -= 0.5;
9721
9875
  this.max += 0.5;
9722
9876
  }
9723
- this.single = single;
9724
9877
  if (!tickPositionsOption && !tickPositioner) {
9725
9878
  this.adjustTickAmount();
9726
9879
  }
@@ -10392,9 +10545,9 @@
10392
10545
  })
10393
10546
  .addClass('highcharts-axis-title')
10394
10547
 
10395
- .css(axisTitleOptions.style)
10548
+ .css(axisTitleOptions.style)
10396
10549
 
10397
- .add(axis.axisGroup);
10550
+ .add(axis.axisGroup);
10398
10551
  axis.axisTitle.isNew = true;
10399
10552
  }
10400
10553
 
@@ -10557,7 +10710,9 @@
10557
10710
  axisOffset[side],
10558
10711
  axis.axisTitleMargin + titleOffset + directionFactor * axis.offset,
10559
10712
  labelOffsetPadded, // #3027
10560
- hasData && tickPositions.length && tickSize ? tickSize[0] : 0 // #4866
10713
+ hasData && tickPositions.length && tickSize ?
10714
+ tickSize[0] + directionFactor * axis.offset :
10715
+ 0 // #4866
10561
10716
  );
10562
10717
 
10563
10718
  // Decide the clipping needed to keep the graph inside the plot area and axis lines
@@ -11052,7 +11207,6 @@
11052
11207
  *
11053
11208
  * License: www.highcharts.com/license
11054
11209
  */
11055
- 'use strict';
11056
11210
  var Axis = H.Axis,
11057
11211
  Date = H.Date,
11058
11212
  dateFormat = H.dateFormat,
@@ -11082,7 +11236,7 @@
11082
11236
  higherRanks = {},
11083
11237
  useUTC = defaultOptions.global.useUTC,
11084
11238
  minYear, // used in months and years as a basis for Date.UTC()
11085
- minDate = new Date(min - getTZOffset(min)),
11239
+ minDate = new Date(min - Math.abs(getTZOffset(min))), // #6278
11086
11240
  makeTime = Date.hcMakeTime,
11087
11241
  interval = normalizedInterval.unitRange,
11088
11242
  count = normalizedInterval.count,
@@ -11313,7 +11467,6 @@
11313
11467
  *
11314
11468
  * License: www.highcharts.com/license
11315
11469
  */
11316
- 'use strict';
11317
11470
  var Axis = H.Axis,
11318
11471
  getMagnitude = H.getMagnitude,
11319
11472
  map = H.map,
@@ -11437,7 +11590,6 @@
11437
11590
  *
11438
11591
  * License: www.highcharts.com/license
11439
11592
  */
11440
- 'use strict';
11441
11593
  var dateFormat = H.dateFormat,
11442
11594
  each = H.each,
11443
11595
  extend = H.extend,
@@ -11828,21 +11980,20 @@
11828
11980
 
11829
11981
  /**
11830
11982
  * Refresh the tooltip's text and position.
11831
- * @param {Object} point
11983
+ * @param {Object|Array} pointOrPoints Rither a point or an array of points
11832
11984
  */
11833
- refresh: function(point, mouseEvent) {
11985
+ refresh: function(pointOrPoints, mouseEvent) {
11834
11986
  var tooltip = this,
11835
- chart = tooltip.chart,
11836
11987
  label,
11837
11988
  options = tooltip.options,
11838
11989
  x,
11839
11990
  y,
11991
+ point = pointOrPoints,
11840
11992
  anchor,
11841
11993
  textConfig = {},
11842
11994
  text,
11843
11995
  pointConfig = [],
11844
11996
  formatter = options.formatter || tooltip.defaultFormatter,
11845
- hoverPoints = chart.hoverPoints,
11846
11997
  shared = tooltip.shared,
11847
11998
  currentSeries;
11848
11999
 
@@ -11856,16 +12007,6 @@
11856
12007
 
11857
12008
  // shared tooltip, array is sent over
11858
12009
  if (shared && !(point.series && point.series.noSharedTooltip)) {
11859
-
11860
- // hide previous hoverPoints and set new
11861
-
11862
- chart.hoverPoints = point;
11863
- if (hoverPoints) {
11864
- each(hoverPoints, function(point) {
11865
- point.setState();
11866
- });
11867
- }
11868
-
11869
12010
  each(point, function(item) {
11870
12011
  item.setState('hover');
11871
12012
 
@@ -11906,7 +12047,7 @@
11906
12047
 
11907
12048
  // update text
11908
12049
  if (tooltip.split) {
11909
- this.renderSplit(text, chart.hoverPoints);
12050
+ this.renderSplit(text, pointOrPoints);
11910
12051
  } else {
11911
12052
  label.attr({
11912
12053
  text: text && text.join ? text.join('') : text
@@ -12201,7 +12342,6 @@
12201
12342
  *
12202
12343
  * License: www.highcharts.com/license
12203
12344
  */
12204
- 'use strict';
12205
12345
  var addEvent = H.addEvent,
12206
12346
  attr = H.attr,
12207
12347
  charts = H.charts,
@@ -12338,91 +12478,57 @@
12338
12478
  });
12339
12479
  return coordinates;
12340
12480
  },
12341
-
12342
12481
  /**
12343
- * With line type charts with a single tracker, get the point closest to the mouse.
12344
- * Run Point.onMouseOver and display tooltip for the point or points.
12482
+ * Collects the points closest to a mouseEvent
12483
+ * @param {Array} series Array of series to gather points from
12484
+ * @param {Boolean} shared True if shared tooltip, otherwise false
12485
+ * @param {Object} e Mouse event which possess a position to compare against
12486
+ * @return {Array} KDPoints sorted by distance
12345
12487
  */
12346
- runPointActions: function(e) {
12347
-
12348
- var pointer = this,
12349
- chart = pointer.chart,
12350
- series = chart.series,
12351
- tooltip = chart.tooltip,
12352
- shared = tooltip ? tooltip.shared : false,
12353
- followPointer,
12354
- updatePosition = true,
12355
- hoverPoint = chart.hoverPoint,
12356
- hoverSeries = chart.hoverSeries,
12357
- i,
12358
- anchor,
12488
+ getKDPoints: function(series, shared, e) {
12489
+ var kdpoints = [],
12359
12490
  noSharedTooltip,
12360
- stickToHoverSeries,
12361
12491
  directTouch,
12362
- kdpoints = [],
12363
- kdpointT;
12364
-
12365
- // For hovering over the empty parts of the plot area (hoverSeries is undefined).
12366
- // If there is one series with point tracking (combo chart), don't go to nearest neighbour.
12367
- if (!shared && !hoverSeries) {
12368
- for (i = 0; i < series.length; i++) {
12369
- if (series[i].directTouch || !series[i].options.stickyTracking) {
12370
- series = [];
12371
- }
12372
- }
12373
- }
12374
-
12375
- // If it has a hoverPoint and that series requires direct touch (like columns, #3899), or we're on
12376
- // a noSharedTooltip series among shared tooltip series (#4546), use the hoverPoint . Otherwise,
12377
- // search the k-d tree.
12378
- stickToHoverSeries = hoverSeries && (shared ? hoverSeries.noSharedTooltip : hoverSeries.directTouch);
12379
- if (stickToHoverSeries && hoverPoint) {
12380
- kdpoints = [hoverPoint];
12492
+ kdpointT,
12493
+ i;
12381
12494
 
12382
- // Handle shared tooltip or cases where a series is not yet hovered
12383
- } else {
12384
- // When we have non-shared tooltip and sticky tracking is disabled,
12385
- // search for the closest point only on hovered series: #5533, #5476
12386
- if (!shared && hoverSeries && !hoverSeries.options.stickyTracking) {
12387
- series = [hoverSeries];
12388
- }
12389
- // Find nearest points on all series
12390
- each(series, function(s) {
12391
- // Skip hidden series
12392
- noSharedTooltip = s.noSharedTooltip && shared;
12393
- directTouch = !shared && s.directTouch;
12394
- if (s.visible && !noSharedTooltip && !directTouch && pick(s.options.enableMouseTracking, true)) { // #3821
12395
- kdpointT = s.searchPoint(e, !noSharedTooltip && s.kdDimensions === 1); // #3828
12396
- if (kdpointT && kdpointT.series) { // Point.series becomes null when reset and before redraw (#5197)
12397
- kdpoints.push(kdpointT);
12398
- }
12495
+ // Find nearest points on all series
12496
+ each(series, function(s) {
12497
+ // Skip hidden series
12498
+ noSharedTooltip = s.noSharedTooltip && shared;
12499
+ directTouch = !shared && s.directTouch;
12500
+ if (s.visible && !noSharedTooltip && !directTouch && pick(s.options.enableMouseTracking, true)) { // #3821
12501
+ kdpointT = s.searchPoint(e, !noSharedTooltip && s.kdDimensions === 1); // #3828
12502
+ if (kdpointT && kdpointT.series) { // Point.series becomes null when reset and before redraw (#5197)
12503
+ kdpoints.push(kdpointT);
12399
12504
  }
12400
- });
12401
-
12402
- // Sort kdpoints by distance to mouse pointer
12403
- kdpoints.sort(function(p1, p2) {
12404
- var isCloserX = p1.distX - p2.distX,
12405
- isCloser = p1.dist - p2.dist,
12406
- isAbove = (p2.series.group && p2.series.group.zIndex) -
12407
- (p1.series.group && p1.series.group.zIndex);
12505
+ }
12506
+ });
12408
12507
 
12409
- // We have two points which are not in the same place on xAxis and shared tooltip:
12410
- if (isCloserX !== 0 && shared) { // #5721
12411
- return isCloserX;
12412
- }
12508
+ // Sort kdpoints by distance to mouse pointer
12509
+ kdpoints.sort(function(p1, p2) {
12510
+ var isCloserX = p1.distX - p2.distX,
12511
+ isCloser = p1.dist - p2.dist,
12512
+ isAbove =
12513
+ (p2.series.group && p2.series.group.zIndex) -
12514
+ (p1.series.group && p1.series.group.zIndex),
12515
+ result;
12516
+
12517
+ // We have two points which are not in the same place on xAxis and shared tooltip:
12518
+ if (isCloserX !== 0 && shared) { // #5721
12519
+ result = isCloserX;
12413
12520
  // Points are not exactly in the same place on x/yAxis:
12414
- if (isCloser !== 0) {
12415
- return isCloser;
12416
- }
12521
+ } else if (isCloser !== 0) {
12522
+ result = isCloser;
12417
12523
  // The same xAxis and yAxis position, sort by z-index:
12418
- if (isAbove !== 0) {
12419
- return isAbove;
12420
- }
12421
-
12524
+ } else if (isAbove !== 0) {
12525
+ result = isAbove;
12422
12526
  // The same zIndex, sort by array index:
12423
- return p1.series.index > p2.series.index ? -1 : 1;
12424
- });
12425
- }
12527
+ } else {
12528
+ result = p1.series.index > p2.series.index ? -1 : 1;
12529
+ }
12530
+ return result;
12531
+ });
12426
12532
 
12427
12533
  // Remove points with different x-positions, required for shared tooltip and crosshairs (#4645):
12428
12534
  if (shared) {
@@ -12433,57 +12539,173 @@
12433
12539
  }
12434
12540
  }
12435
12541
  }
12542
+ return kdpoints;
12543
+ },
12544
+ getPointFromEvent: function(e) {
12545
+ var target = e.target,
12546
+ point;
12547
+
12548
+ while (target && !point) {
12549
+ point = target.point;
12550
+ target = target.parentNode;
12551
+ }
12552
+ return point;
12553
+ },
12436
12554
 
12437
- // Refresh tooltip for kdpoint if new hover point or tooltip was hidden // #3926, #4200
12438
- if (kdpoints[0] && (kdpoints[0] !== this.prevKDPoint || (tooltip && tooltip.isHidden))) {
12439
- // Draw tooltip if necessary
12440
- if (shared && !kdpoints[0].series.noSharedTooltip) {
12441
- // Do mouseover on all points (#3919, #3985, #4410, #5622)
12442
- for (i = 0; i < kdpoints.length; i++) {
12443
- kdpoints[i].onMouseOver(e, kdpoints[i] !== ((hoverSeries && hoverSeries.directTouch && hoverPoint) || kdpoints[0]));
12444
- }
12555
+ getHoverData: function(existingHoverPoint, existingHoverSeries, series, isDirectTouch, shared, e) {
12556
+ var i,
12557
+ hoverPoint = existingHoverPoint,
12558
+ hoverSeries = existingHoverSeries,
12559
+ hoverPoints;
12445
12560
 
12446
- if (kdpoints.length && tooltip) {
12447
- // Keep the order of series in tooltip:
12448
- tooltip.refresh(kdpoints.sort(function(p1, p2) {
12449
- return p1.series.index - p2.series.index;
12450
- }), e);
12561
+ // If it has a hoverPoint and that series requires direct touch (like columns, #3899), or we're on
12562
+ // a noSharedTooltip series among shared tooltip series (#4546), use the hoverPoint . Otherwise,
12563
+ // search the k-d tree.
12564
+ // Handle shared tooltip or cases where a series is not yet hovered
12565
+ if (isDirectTouch) {
12566
+ if (shared) {
12567
+ hoverPoints = [];
12568
+ each(series, function(s) {
12569
+ // Skip hidden series
12570
+ var noSharedTooltip = s.noSharedTooltip && shared,
12571
+ directTouch = !shared && s.directTouch,
12572
+ kdpointT;
12573
+ if (s.visible && !noSharedTooltip && !directTouch && pick(s.options.enableMouseTracking, true)) { // #3821
12574
+ kdpointT = s.searchKDTree({
12575
+ clientX: hoverPoint.clientX,
12576
+ plotY: hoverPoint.plotY
12577
+ }, !noSharedTooltip && s.kdDimensions === 1);
12578
+ if (kdpointT && kdpointT.series) { // Point.series becomes null when reset and before redraw (#5197)
12579
+ hoverPoints.push(kdpointT);
12580
+ }
12581
+ }
12582
+ });
12583
+ // If kdTree is not built
12584
+ if (hoverPoints.length === 0) {
12585
+ hoverPoints = [hoverPoint];
12451
12586
  }
12452
12587
  } else {
12453
- if (tooltip) {
12454
- tooltip.refresh(kdpoints[0], e);
12455
- }
12456
- if (!hoverSeries || !hoverSeries.directTouch) { // #4448
12457
- kdpoints[0].onMouseOver(e);
12588
+ hoverPoints = [hoverPoint];
12589
+ }
12590
+ } else if (hoverSeries && !hoverSeries.options.stickyTracking) {
12591
+ hoverPoints = this.getKDPoints([hoverSeries], shared, e);
12592
+ hoverPoint = hoverPoints[0];
12593
+ hoverSeries = hoverPoint && hoverPoint.series;
12594
+ } else {
12595
+ if (!shared) {
12596
+ // For hovering over the empty parts of the plot area (hoverSeries is undefined).
12597
+ // If there is one series with point tracking (combo chart), don't go to nearest neighbour.
12598
+ if (!hoverSeries) {
12599
+ for (i = 0; i < series.length; i++) {
12600
+ if (series[i].directTouch || !series[i].options.stickyTracking) {
12601
+ series = [];
12602
+ }
12603
+ }
12604
+ // When we have non-shared tooltip and sticky tracking is disabled,
12605
+ // search for the closest point only on hovered series: #5533, #5476
12606
+ } else if (!hoverSeries.options.stickyTracking) {
12607
+ series = [hoverSeries];
12458
12608
  }
12459
12609
  }
12460
- this.prevKDPoint = kdpoints[0];
12461
- updatePosition = false;
12610
+ hoverPoints = this.getKDPoints(series, shared, e);
12611
+ hoverPoint = hoverPoints[0];
12612
+ hoverSeries = hoverPoint && hoverPoint.series;
12462
12613
  }
12463
- // Update positions (regardless of kdpoint or hoverPoint)
12464
- if (updatePosition) {
12465
- followPointer = hoverSeries && hoverSeries.tooltipOptions.followPointer;
12466
- if (tooltip && followPointer && !tooltip.isHidden) {
12467
- anchor = tooltip.getAnchor([{}], e);
12468
- tooltip.updatePosition({
12469
- plotX: anchor[0],
12470
- plotY: anchor[1]
12471
- });
12614
+ // Keep the order of series in tooltip
12615
+ // Must be done after assigning of hoverPoint
12616
+ hoverPoints.sort(function(p1, p2) {
12617
+ return p1.series.index - p2.series.index;
12618
+ });
12619
+
12620
+ return {
12621
+ hoverPoint: hoverPoint,
12622
+ hoverSeries: hoverSeries,
12623
+ hoverPoints: hoverPoints
12624
+ };
12625
+ },
12626
+ /**
12627
+ * With line type charts with a single tracker, get the point closest to the mouse.
12628
+ * Run Point.onMouseOver and display tooltip for the point or points.
12629
+ */
12630
+ runPointActions: function(e, p) {
12631
+ var pointer = this,
12632
+ chart = pointer.chart,
12633
+ series = chart.series,
12634
+ tooltip = chart.tooltip,
12635
+ shared = tooltip ? tooltip.shared : false,
12636
+ hoverPoint = p || chart.hoverPoint,
12637
+ hoverSeries = hoverPoint && hoverPoint.series || chart.hoverSeries,
12638
+ // onMouseOver or already hovering a series with directTouch
12639
+ isDirectTouch = !!p || (hoverSeries && hoverSeries.directTouch),
12640
+ hoverData = this.getHoverData(hoverPoint, hoverSeries, series, isDirectTouch, shared, e),
12641
+ useSharedTooltip,
12642
+ followPointer,
12643
+ anchor,
12644
+ points;
12645
+
12646
+ // Update variables from hoverData.
12647
+ hoverPoint = hoverData.hoverPoint;
12648
+ hoverSeries = hoverData.hoverSeries;
12649
+ followPointer = hoverSeries && hoverSeries.tooltipOptions.followPointer;
12650
+ useSharedTooltip = shared && hoverPoint && !hoverPoint.series.noSharedTooltip;
12651
+ points = useSharedTooltip ? hoverData.hoverPoints : [hoverPoint];
12652
+
12653
+ // Refresh tooltip for kdpoint if new hover point or tooltip was hidden // #3926, #4200
12654
+ if (
12655
+ hoverPoint &&
12656
+ // !(hoverSeries && hoverSeries.directTouch) &&
12657
+ (hoverPoint !== chart.hoverPoint || (tooltip && tooltip.isHidden))
12658
+ ) {
12659
+ each(chart.hoverPoints || [], function(p) {
12660
+ if (H.inArray(p, points) === -1) {
12661
+ p.setState();
12662
+ }
12663
+ });
12664
+ // Do mouseover on all points (#3919, #3985, #4410, #5622)
12665
+ each(points || [], function(p) {
12666
+ p.setState('hover');
12667
+ });
12668
+ // set normal state to previous series
12669
+ if (chart.hoverSeries !== hoverSeries) {
12670
+ hoverSeries.onMouseOver();
12671
+ }
12672
+
12673
+ // If tracking is on series in stead of on each point,
12674
+ // fire mouseOver on hover point.
12675
+ if (hoverSeries && !hoverSeries.directTouch) { // #4448
12676
+ if (chart.hoverPoint) {
12677
+ chart.hoverPoint.firePointEvent('mouseOut');
12678
+ }
12679
+ hoverPoint.firePointEvent('mouseOver');
12472
12680
  }
12681
+ chart.hoverPoints = points;
12682
+ chart.hoverPoint = hoverPoint;
12683
+ // Draw tooltip if necessary
12684
+ if (tooltip) {
12685
+ tooltip.refresh(useSharedTooltip ? points : hoverPoint, e);
12686
+ }
12687
+ // Update positions (regardless of kdpoint or hoverPoint)
12688
+ } else if (followPointer && tooltip && !tooltip.isHidden) {
12689
+ anchor = tooltip.getAnchor([{}], e);
12690
+ tooltip.updatePosition({
12691
+ plotX: anchor[0],
12692
+ plotY: anchor[1]
12693
+ });
12473
12694
  }
12474
12695
 
12475
12696
  // Start the event listener to pick up the tooltip and crosshairs
12476
12697
  if (!pointer.unDocMouseMove) {
12477
12698
  pointer.unDocMouseMove = addEvent(doc, 'mousemove', function(e) {
12478
- if (charts[H.hoverChartIndex]) {
12479
- charts[H.hoverChartIndex].pointer.onDocumentMouseMove(e);
12699
+ var chart = charts[H.hoverChartIndex];
12700
+ if (chart) {
12701
+ chart.pointer.onDocumentMouseMove(e);
12480
12702
  }
12481
12703
  });
12482
12704
  }
12483
12705
 
12484
12706
  // Crosshair. For each hover point, loop over axes and draw cross if that point
12485
12707
  // belongs to the axis (#4927).
12486
- each(shared ? kdpoints : [pick(hoverPoint, kdpoints[0])], function drawPointCrosshair(point) { // #5269
12708
+ each(points, function drawPointCrosshair(point) { // #5269
12487
12709
  each(chart.axes, function drawAxisCrosshair(axis) {
12488
12710
  // In case of snap = false, point is undefined, and we draw the crosshair anyway (#5066)
12489
12711
  if (!point || point.series && point.series[axis.coll] === axis) { // #5658
@@ -12560,7 +12782,7 @@
12560
12782
  axis.hideCrosshair();
12561
12783
  });
12562
12784
 
12563
- pointer.hoverX = pointer.prevKDPoint = chart.hoverPoints = chart.hoverPoint = null;
12785
+ pointer.hoverX = chart.hoverPoints = chart.hoverPoint = null;
12564
12786
  }
12565
12787
  },
12566
12788
 
@@ -12981,7 +13203,6 @@
12981
13203
  *
12982
13204
  * License: www.highcharts.com/license
12983
13205
  */
12984
- 'use strict';
12985
13206
  var charts = H.charts,
12986
13207
  each = H.each,
12987
13208
  extend = H.extend,
@@ -13259,7 +13480,6 @@
13259
13480
  *
13260
13481
  * License: www.highcharts.com/license
13261
13482
  */
13262
- 'use strict';
13263
13483
  var addEvent = H.addEvent,
13264
13484
  charts = H.charts,
13265
13485
  css = H.css,
@@ -13379,7 +13599,6 @@
13379
13599
  *
13380
13600
  * License: www.highcharts.com/license
13381
13601
  */
13382
- 'use strict';
13383
13602
  var Legend,
13384
13603
 
13385
13604
  addEvent = H.addEvent,
@@ -13387,7 +13606,6 @@
13387
13606
  discardElement = H.discardElement,
13388
13607
  defined = H.defined,
13389
13608
  each = H.each,
13390
- extend = H.extend,
13391
13609
  isFirefox = H.isFirefox,
13392
13610
  marginNames = H.marginNames,
13393
13611
  merge = H.merge,
@@ -13580,7 +13798,17 @@
13580
13798
  each(['legendItem', 'legendGroup'], destroyItems, item);
13581
13799
  });
13582
13800
 
13583
- each(['box', 'title', 'group'], destroyItems, this);
13801
+ // Destroy legend elements
13802
+ each([
13803
+ 'clipRect',
13804
+ 'up',
13805
+ 'down',
13806
+ 'pager',
13807
+ 'nav',
13808
+ 'box',
13809
+ 'title',
13810
+ 'group'
13811
+ ], destroyItems, this);
13584
13812
  this.display = null; // Reset in .render on update.
13585
13813
  },
13586
13814
 
@@ -13628,9 +13856,9 @@
13628
13856
  zIndex: 1
13629
13857
  })
13630
13858
 
13631
- .css(titleOptions.style)
13859
+ .css(titleOptions.style)
13632
13860
 
13633
- .add(this.group);
13861
+ .add(this.group);
13634
13862
  }
13635
13863
  bBox = this.title.getBBox();
13636
13864
  titleHeight = bBox.height;
@@ -13702,15 +13930,15 @@
13702
13930
 
13703
13931
  // Generate the list item text and add it to the group
13704
13932
  item.legendItem = li = renderer.text(
13705
- '',
13706
- ltr ? symbolWidth + symbolPadding : -symbolPadding,
13707
- legend.baseline || 0,
13708
- useHTML
13709
- )
13933
+ '',
13934
+ ltr ? symbolWidth + symbolPadding : -symbolPadding,
13935
+ legend.baseline || 0,
13936
+ useHTML
13937
+ )
13710
13938
 
13711
- .css(merge(item.visible ? itemStyle : itemHiddenStyle)) // merge to prevent modifying original (#1021)
13939
+ .css(merge(item.visible ? itemStyle : itemHiddenStyle)) // merge to prevent modifying original (#1021)
13712
13940
 
13713
- .attr({
13941
+ .attr({
13714
13942
  align: ltr ? 'left' : 'right',
13715
13943
  zIndex: 2
13716
13944
  })
@@ -13982,10 +14210,10 @@
13982
14210
  }*/
13983
14211
 
13984
14212
  if (display) {
13985
- legendGroup.align(extend({
14213
+ legendGroup.align(merge(options, {
13986
14214
  width: legendWidth,
13987
14215
  height: legendHeight
13988
- }, options), true, 'spacingBox');
14216
+ }), true, 'spacingBox');
13989
14217
  }
13990
14218
 
13991
14219
  if (!chart.isResizing) {
@@ -14093,9 +14321,9 @@
14093
14321
  this.pager = renderer.text('', 15, 10)
14094
14322
  .addClass('highcharts-legend-navigation')
14095
14323
 
14096
- .css(navOptions.style)
14324
+ .css(navOptions.style)
14097
14325
 
14098
- .add(nav);
14326
+ .add(nav);
14099
14327
  this.down = renderer.symbol('triangle-down', 0, 0, arrowSize, arrowSize)
14100
14328
  .on('click', function() {
14101
14329
  legend.scroll(1, animation);
@@ -14111,7 +14339,7 @@
14111
14339
  // Reset
14112
14340
  } else if (nav) {
14113
14341
  clipToHeight();
14114
- nav.hide();
14342
+ this.nav = nav.destroy(); // #6322
14115
14343
  this.scrollGroup.attr({
14116
14344
  translateY: 1
14117
14345
  });
@@ -14329,7 +14557,6 @@
14329
14557
  *
14330
14558
  * License: www.highcharts.com/license
14331
14559
  */
14332
- 'use strict';
14333
14560
  var addEvent = H.addEvent,
14334
14561
  animate = H.animate,
14335
14562
  animObject = H.animObject,
@@ -14416,7 +14643,6 @@
14416
14643
  options = merge(defaultOptions, userOptions); // do the merge
14417
14644
  options.series = userOptions.series = seriesOptions; // set back the series data
14418
14645
  this.userOptions = userOptions;
14419
- this.respRules = [];
14420
14646
 
14421
14647
  var optionsChart = options.chart;
14422
14648
 
@@ -14565,8 +14791,7 @@
14565
14791
  hasDirtyStacks,
14566
14792
  hasCartesianSeries = chart.hasCartesianSeries,
14567
14793
  isDirtyBox = chart.isDirtyBox,
14568
- seriesLength = series.length,
14569
- i = seriesLength,
14794
+ i,
14570
14795
  serie,
14571
14796
  renderer = chart.renderer,
14572
14797
  isHiddenChart = renderer.isHidden(),
@@ -14587,6 +14812,7 @@
14587
14812
  chart.layOutTitles();
14588
14813
 
14589
14814
  // link stacked series
14815
+ i = series.length;
14590
14816
  while (i--) {
14591
14817
  serie = series[i];
14592
14818
 
@@ -14600,7 +14826,7 @@
14600
14826
  }
14601
14827
  }
14602
14828
  if (hasDirtyStacks) { // mark others as dirty
14603
- i = seriesLength;
14829
+ i = series.length;
14604
14830
  while (i--) {
14605
14831
  serie = series[i];
14606
14832
  if (serie.options.stacking) {
@@ -14948,7 +15174,10 @@
14948
15174
  );
14949
15175
  chart.chartHeight = Math.max(
14950
15176
  0,
14951
- heightOption || chart.containerHeight || 400
15177
+ H.relativeLength(
15178
+ heightOption,
15179
+ chart.chartWidth
15180
+ ) || chart.containerHeight || 400
14952
15181
  );
14953
15182
  },
14954
15183
 
@@ -15735,9 +15964,9 @@
15735
15964
  zIndex: 8
15736
15965
  })
15737
15966
 
15738
- .css(credits.style)
15967
+ .css(credits.style)
15739
15968
 
15740
- .add()
15969
+ .add()
15741
15970
  .align(credits.position);
15742
15971
 
15743
15972
  // Dynamically update
@@ -15931,7 +16160,6 @@
15931
16160
  *
15932
16161
  * License: www.highcharts.com/license
15933
16162
  */
15934
- 'use strict';
15935
16163
  var Point,
15936
16164
 
15937
16165
  each = H.each,
@@ -16282,7 +16510,6 @@
16282
16510
  *
16283
16511
  * License: www.highcharts.com/license
16284
16512
  */
16285
- 'use strict';
16286
16513
  var addEvent = H.addEvent,
16287
16514
  animObject = H.animObject,
16288
16515
  arrayMax = H.arrayMax,
@@ -16415,6 +16642,9 @@
16415
16642
  states: { // states for the entire series
16416
16643
  hover: {
16417
16644
  //enabled: false,
16645
+ animation: {
16646
+ duration: 50
16647
+ },
16418
16648
  lineWidthPlus: 1,
16419
16649
  marker: {
16420
16650
  // lineWidth: base + 1,
@@ -16440,7 +16670,7 @@
16440
16670
  //ySuffix: ''
16441
16671
  //}
16442
16672
  turboThreshold: 1000
16443
- // zIndex: null
16673
+ // zIndex: null
16444
16674
 
16445
16675
 
16446
16676
  }, /** @lends Series.prototype */ {
@@ -17122,7 +17352,7 @@
17122
17352
 
17123
17353
  // For points within the visible range, including the first point outside the
17124
17354
  // visible range, consider y extremes
17125
- validValue = (isNumber(y, true) || isArray(y)) && (!yAxis.isLog || (y.length || y > 0));
17355
+ validValue = (isNumber(y, true) || isArray(y)) && (!yAxis.positiveValuesOnly || (y.length || y > 0));
17126
17356
  withinRange = this.getExtremesFromAll || this.options.getExtremesFromAll || this.cropped ||
17127
17357
  ((xData[i + 1] || x) >= xMin && (xData[i - 1] || x) <= xMax);
17128
17358
 
@@ -17196,7 +17426,7 @@
17196
17426
  stackValues;
17197
17427
 
17198
17428
  // Discard disallowed y values for log axes (#3434)
17199
- if (yAxis.isLog && yValue !== null && yValue <= 0) {
17429
+ if (yAxis.positiveValuesOnly && yValue !== null && yValue <= 0) {
17200
17430
  point.isNull = true;
17201
17431
  }
17202
17432
 
@@ -17224,7 +17454,7 @@
17224
17454
  if (yBottom === stackThreshold && stackIndicator.key === stack[xValue].base) {
17225
17455
  yBottom = pick(threshold, yAxis.min);
17226
17456
  }
17227
- if (yAxis.isLog && yBottom <= 0) { // #1200, #1232
17457
+ if (yAxis.positiveValuesOnly && yBottom <= 0) { // #1200, #1232
17228
17458
  yBottom = null;
17229
17459
  }
17230
17460
 
@@ -17431,7 +17661,8 @@
17431
17661
  globallyEnabled = pick(
17432
17662
  seriesMarkerOptions.enabled,
17433
17663
  xAxis.isRadial ? true : null,
17434
- series.closestPointRangePx > 2 * seriesMarkerOptions.radius
17664
+ // Use larger or equal as radius is null in bubbles (#6321)
17665
+ series.closestPointRangePx >= 2 * seriesMarkerOptions.radius
17435
17666
  );
17436
17667
 
17437
17668
  if (seriesMarkerOptions.enabled !== false || series._hasPointMarkers) {
@@ -17982,6 +18213,15 @@
17982
18213
  function setInvert() {
17983
18214
  each(['group', 'markerGroup'], function(groupName) {
17984
18215
  if (series[groupName]) {
18216
+
18217
+ // VML/HTML needs explicit attributes for flipping
18218
+ if (chart.renderer.isVML) {
18219
+ series[groupName].attr({
18220
+ width: series.yAxis.len,
18221
+ height: series.xAxis.len
18222
+ });
18223
+ }
18224
+
17985
18225
  series[groupName].width = series.yAxis.len;
17986
18226
  series[groupName].height = series.xAxis.len;
17987
18227
  series[groupName].invert(inverted);
@@ -18329,7 +18569,6 @@
18329
18569
  *
18330
18570
  * License: www.highcharts.com/license
18331
18571
  */
18332
- 'use strict';
18333
18572
  var Axis = H.Axis,
18334
18573
  Chart = H.Chart,
18335
18574
  correctFloat = H.correctFloat,
@@ -18815,7 +19054,6 @@
18815
19054
  *
18816
19055
  * License: www.highcharts.com/license
18817
19056
  */
18818
- 'use strict';
18819
19057
  var addEvent = H.addEvent,
18820
19058
  animate = H.animate,
18821
19059
  Axis = H.Axis,
@@ -19063,6 +19301,7 @@
19063
19301
  // options.title => chart.title
19064
19302
  // options.tooltip => chart.tooltip
19065
19303
  // options.subtitle => chart.subtitle
19304
+ // options.mapNavigation => chart.mapNavigation
19066
19305
  // options.navigator => chart.navigator
19067
19306
  // options.scrollbar => chart.scrollbar
19068
19307
  for (key in options) {
@@ -19094,7 +19333,6 @@
19094
19333
  // item in the collection, so setting one series without an id, will
19095
19334
  // update the first series in the chart. Setting two series without
19096
19335
  // an id will update the first and the second respectively (#6019)
19097
- // // docs: New behaviour for unidentified items, add it to docs for
19098
19336
  // chart.update and responsive.
19099
19337
  each(['xAxis', 'yAxis', 'series'], function(coll) {
19100
19338
  if (options[coll]) {
@@ -19194,9 +19432,15 @@
19194
19432
  i = point.index;
19195
19433
  series.updateParallelArrays(point, i);
19196
19434
 
19197
- // Record the options to options.data. If there is an object from before,
19198
- // use point options, otherwise use raw options. (#4701)
19199
- seriesOptions.data[i] = isObject(seriesOptions.data[i], true) ? point.options : options;
19435
+ // Record the options to options.data. If the old or the new config
19436
+ // is an object, use point options, otherwise use raw options
19437
+ // (#4701, #4916).
19438
+ seriesOptions.data[i] = (
19439
+ isObject(seriesOptions.data[i], true) ||
19440
+ isObject(options, true)
19441
+ ) ?
19442
+ point.options :
19443
+ options;
19200
19444
 
19201
19445
  // redraw
19202
19446
  series.isDirty = series.isDirtyData = true;
@@ -19403,7 +19647,7 @@
19403
19647
  // must use user options when changing type because this.options is merged
19404
19648
  // in with type specific plotOptions
19405
19649
  oldOptions = this.userOptions,
19406
- oldType = this.type,
19650
+ oldType = this.oldType || this.type,
19407
19651
  newType = newOptions.type || oldOptions.type || chart.options.chart.type,
19408
19652
  proto = seriesTypes[oldType].prototype,
19409
19653
  preserve = ['group', 'markerGroup', 'dataLabelsGroup'],
@@ -19443,6 +19687,7 @@
19443
19687
  });
19444
19688
 
19445
19689
  this.init(chart, newOptions);
19690
+ this.oldType = oldType;
19446
19691
  chart.linkSeries(); // Links are lost in this.remove (#3028)
19447
19692
  if (pick(redraw, true)) {
19448
19693
  chart.redraw(false);
@@ -19533,7 +19778,6 @@
19533
19778
  *
19534
19779
  * License: www.highcharts.com/license
19535
19780
  */
19536
- 'use strict';
19537
19781
  var color = H.color,
19538
19782
  each = H.each,
19539
19783
  LegendSymbolMixin = H.LegendSymbolMixin,
@@ -19550,10 +19794,10 @@
19550
19794
  seriesType('area', 'line', {
19551
19795
  softThreshold: false,
19552
19796
  threshold: 0
19553
- // trackByArea: false,
19554
- // lineColor: null, // overrides color, but lets fillColor be unaltered
19555
- // fillOpacity: 0.75,
19556
- // fillColor: null
19797
+ // trackByArea: false,
19798
+ // lineColor: null, // overrides color, but lets fillColor be unaltered
19799
+ // fillOpacity: 0.75,
19800
+ // fillColor: null
19557
19801
  }, /** @lends seriesTypes.area.prototype */ {
19558
19802
  singleStacks: false,
19559
19803
  /**
@@ -19658,11 +19902,11 @@
19658
19902
  // When reversedStacks is true, loop up, else loop down
19659
19903
  i += upOrDown;
19660
19904
  }
19661
-
19662
- y = yAxis.toPixels(y, true);
19905
+ y = yAxis.translate(y, 0, 1, 0, 1); // #6272
19663
19906
  segment.push({
19664
19907
  isNull: true,
19665
- plotX: xAxis.toPixels(x, true),
19908
+ plotX: xAxis.translate(x, 0, 0, 0, 1), // #6272
19909
+ x: x,
19666
19910
  plotY: y,
19667
19911
  yBottom: y
19668
19912
  });
@@ -19723,7 +19967,8 @@
19723
19967
  graphPoints.push({
19724
19968
  plotX: plotX,
19725
19969
  plotY: top === null ? translatedThreshold : yAxis.getThreshold(top),
19726
- isNull: isNull
19970
+ isNull: isNull,
19971
+ isCliff: true
19727
19972
  });
19728
19973
  bottomPoints.push({
19729
19974
  plotX: plotX,
@@ -19780,6 +20025,7 @@
19780
20025
 
19781
20026
  areaPath.xMap = topPath.xMap;
19782
20027
  this.areaPath = areaPath;
20028
+
19783
20029
  return graphPath;
19784
20030
  },
19785
20031
 
@@ -19863,7 +20109,6 @@
19863
20109
  *
19864
20110
  * License: www.highcharts.com/license
19865
20111
  */
19866
- 'use strict';
19867
20112
  var pick = H.pick,
19868
20113
  seriesType = H.seriesType;
19869
20114
 
@@ -19890,7 +20135,10 @@
19890
20135
  ret;
19891
20136
 
19892
20137
  function doCurve(otherPoint) {
19893
- return otherPoint && !otherPoint.isNull && otherPoint.doCurve !== false;
20138
+ return otherPoint &&
20139
+ !otherPoint.isNull &&
20140
+ otherPoint.doCurve !== false &&
20141
+ !point.isCliff; // #6387, area splines next to null
19894
20142
  }
19895
20143
 
19896
20144
  // Find control points
@@ -19999,7 +20247,6 @@
19999
20247
  *
20000
20248
  * License: www.highcharts.com/license
20001
20249
  */
20002
- 'use strict';
20003
20250
  var areaProto = H.seriesTypes.area.prototype,
20004
20251
  defaultPlotOptions = H.defaultPlotOptions,
20005
20252
  LegendSymbolMixin = H.LegendSymbolMixin,
@@ -20022,7 +20269,6 @@
20022
20269
  *
20023
20270
  * License: www.highcharts.com/license
20024
20271
  */
20025
- 'use strict';
20026
20272
  var animObject = H.animObject,
20027
20273
  color = H.color,
20028
20274
  each = H.each,
@@ -20082,7 +20328,7 @@
20082
20328
  threshold: 0,
20083
20329
 
20084
20330
  borderColor: '#ffffff'
20085
- // borderWidth: 1
20331
+ // borderWidth: 1
20086
20332
 
20087
20333
 
20088
20334
  }, /** @lends seriesTypes.column.prototype */ {
@@ -20343,7 +20589,10 @@
20343
20589
 
20344
20590
  // Select or hover states
20345
20591
  if (state) {
20346
- stateOptions = options.states[state];
20592
+ stateOptions = merge(
20593
+ options.states[state],
20594
+ point.options.states && point.options.states[state] || {} // #6401
20595
+ );
20347
20596
  brightness = stateOptions.brightness;
20348
20597
  fill = stateOptions.color ||
20349
20598
  (brightness !== undefined && color(fill).brighten(stateOptions.brightness).get()) ||
@@ -20398,9 +20647,6 @@
20398
20647
 
20399
20648
  } else {
20400
20649
  point.graphic = graphic = renderer[point.shapeType](shapeArgs)
20401
- .attr({
20402
- 'class': point.getClassName()
20403
- })
20404
20650
  .add(point.group || series.group);
20405
20651
  }
20406
20652
 
@@ -20411,6 +20657,9 @@
20411
20657
  .shadow(options.shadow, null, options.stacking && !options.borderRadius);
20412
20658
 
20413
20659
 
20660
+ graphic.addClass(point.getClassName(), true);
20661
+
20662
+
20414
20663
  } else if (graphic) {
20415
20664
  point.graphic = graphic.destroy(); // #1269
20416
20665
  }
@@ -20486,7 +20735,6 @@
20486
20735
  *
20487
20736
  * License: www.highcharts.com/license
20488
20737
  */
20489
- 'use strict';
20490
20738
 
20491
20739
  var seriesType = H.seriesType;
20492
20740
 
@@ -20504,7 +20752,6 @@
20504
20752
  *
20505
20753
  * License: www.highcharts.com/license
20506
20754
  */
20507
- 'use strict';
20508
20755
  var Series = H.Series,
20509
20756
  seriesType = H.seriesType;
20510
20757
  /**
@@ -20545,7 +20792,6 @@
20545
20792
  *
20546
20793
  * License: www.highcharts.com/license
20547
20794
  */
20548
- 'use strict';
20549
20795
  var pick = H.pick,
20550
20796
  relativeLength = H.relativeLength;
20551
20797
 
@@ -20595,7 +20841,6 @@
20595
20841
  *
20596
20842
  * License: www.highcharts.com/license
20597
20843
  */
20598
- 'use strict';
20599
20844
  var addEvent = H.addEvent,
20600
20845
  CenteredSeriesMixin = H.CenteredSeriesMixin,
20601
20846
  defined = H.defined,
@@ -20633,7 +20878,7 @@
20633
20878
  },
20634
20879
  // softConnector: true,
20635
20880
  x: 0
20636
- // y: 0
20881
+ // y: 0
20637
20882
  },
20638
20883
  ignoreHiddenPoint: true,
20639
20884
  //innerSize: 0,
@@ -20880,8 +21125,9 @@
20880
21125
  shapeArgs = point.shapeArgs;
20881
21126
 
20882
21127
 
20883
- // if the point is sliced, use special translation, else use plot area traslation
20884
- groupTranslation = point.sliced ? point.slicedTranslation : {};
21128
+ // If the point is sliced, use special translation, else use
21129
+ // plot area traslation
21130
+ groupTranslation = point.getTranslate();
20885
21131
 
20886
21132
 
20887
21133
  // Put the shadow behind all points
@@ -20902,13 +21148,12 @@
20902
21148
  graphic
20903
21149
  .setRadialReference(series.center)
20904
21150
 
20905
- .attr(pointAttr)
21151
+ .attr(pointAttr)
20906
21152
 
20907
- .animate(extend(shapeArgs, groupTranslation));
21153
+ .animate(extend(shapeArgs, groupTranslation));
20908
21154
  } else {
20909
21155
 
20910
21156
  point.graphic = graphic = renderer[point.shapeType](shapeArgs)
20911
- .addClass(point.getClassName())
20912
21157
  .setRadialReference(series.center)
20913
21158
  .attr(groupTranslation)
20914
21159
  .add(series.group);
@@ -20928,6 +21173,9 @@
20928
21173
  .shadow(shadow, shadowGroup);
20929
21174
 
20930
21175
  }
21176
+
21177
+ graphic.addClass(point.getClassName());
21178
+
20931
21179
  }
20932
21180
  });
20933
21181
 
@@ -21043,8 +21291,7 @@
21043
21291
  slice: function(sliced, redraw, animation) {
21044
21292
  var point = this,
21045
21293
  series = point.series,
21046
- chart = series.chart,
21047
- translation;
21294
+ chart = series.chart;
21048
21295
 
21049
21296
  setAnimation(animation, chart);
21050
21297
 
@@ -21055,20 +21302,22 @@
21055
21302
  point.sliced = point.options.sliced = sliced = defined(sliced) ? sliced : !point.sliced;
21056
21303
  series.options.data[inArray(point, series.data)] = point.options; // update userOptions.data
21057
21304
 
21058
- translation = sliced ? point.slicedTranslation : {
21059
- translateX: 0,
21060
- translateY: 0
21061
- };
21062
-
21063
- point.graphic.animate(translation);
21305
+ point.graphic.animate(this.getTranslate());
21064
21306
 
21065
21307
 
21066
21308
  if (point.shadowGroup) {
21067
- point.shadowGroup.animate(translation);
21309
+ point.shadowGroup.animate(this.getTranslate());
21068
21310
  }
21069
21311
 
21070
21312
  },
21071
21313
 
21314
+ getTranslate: function() {
21315
+ return this.sliced ? this.slicedTranslation : {
21316
+ translateX: 0,
21317
+ translateY: 0
21318
+ };
21319
+ },
21320
+
21072
21321
  haloPath: function(size) {
21073
21322
  var shapeArgs = this.shapeArgs;
21074
21323
 
@@ -21093,7 +21342,6 @@
21093
21342
  *
21094
21343
  * License: www.highcharts.com/license
21095
21344
  */
21096
- 'use strict';
21097
21345
  var addEvent = H.addEvent,
21098
21346
  arrayMax = H.arrayMax,
21099
21347
  defined = H.defined,
@@ -21584,6 +21832,21 @@
21584
21832
  return;
21585
21833
  }
21586
21834
 
21835
+ // Reset all labels that have been shortened
21836
+ each(data, function(point) {
21837
+ if (point.dataLabel && point.visible && point.dataLabel.shortened) {
21838
+ point.dataLabel
21839
+ .attr({
21840
+ width: 'auto'
21841
+ }).css({
21842
+ width: 'auto',
21843
+ textOverflow: 'clip'
21844
+ });
21845
+ point.dataLabel.shortened = false;
21846
+ }
21847
+ });
21848
+
21849
+
21587
21850
  // run parent method
21588
21851
  Series.prototype.drawDataLabels.apply(series);
21589
21852
 
@@ -21608,6 +21871,7 @@
21608
21871
  length = points.length,
21609
21872
  positions,
21610
21873
  naturalY,
21874
+ sideOverflow,
21611
21875
  size;
21612
21876
 
21613
21877
  if (!length) {
@@ -21683,24 +21947,39 @@
21683
21947
 
21684
21948
  // Detect overflowing data labels
21685
21949
  if (series.options.size === null) {
21686
- dataLabelWidth = dataLabel.width;
21950
+ dataLabelWidth = dataLabel.getBBox().width;
21951
+
21952
+ sideOverflow = null;
21687
21953
  // Overflow left
21688
21954
  if (x - dataLabelWidth < connectorPadding) {
21689
- overflow[3] = Math.max(Math.round(dataLabelWidth - x + connectorPadding), overflow[3]);
21955
+ sideOverflow = Math.round(
21956
+ dataLabelWidth - x + connectorPadding
21957
+ );
21958
+ overflow[3] = Math.max(sideOverflow, overflow[3]);
21690
21959
 
21691
21960
  // Overflow right
21692
21961
  } else if (x + dataLabelWidth > plotWidth - connectorPadding) {
21693
- overflow[1] = Math.max(Math.round(x + dataLabelWidth - plotWidth + connectorPadding), overflow[1]);
21962
+ sideOverflow = Math.round(
21963
+ x + dataLabelWidth - plotWidth + connectorPadding
21964
+ );
21965
+ overflow[1] = Math.max(sideOverflow, overflow[1]);
21694
21966
  }
21695
21967
 
21696
21968
  // Overflow top
21697
21969
  if (y - labelHeight / 2 < 0) {
21698
- overflow[0] = Math.max(Math.round(-y + labelHeight / 2), overflow[0]);
21970
+ overflow[0] = Math.max(
21971
+ Math.round(-y + labelHeight / 2),
21972
+ overflow[0]
21973
+ );
21699
21974
 
21700
21975
  // Overflow left
21701
21976
  } else if (y + labelHeight / 2 > plotHeight) {
21702
- overflow[2] = Math.max(Math.round(y + labelHeight / 2 - plotHeight), overflow[2]);
21977
+ overflow[2] = Math.max(
21978
+ Math.round(y + labelHeight / 2 - plotHeight),
21979
+ overflow[2]
21980
+ );
21703
21981
  }
21982
+ dataLabel.sideOverflow = sideOverflow;
21704
21983
  }
21705
21984
  } // for each point
21706
21985
  }); // for each half
@@ -21784,10 +22063,22 @@
21784
22063
  each(this.points, function(point) {
21785
22064
  var dataLabel = point.dataLabel,
21786
22065
  _pos;
21787
-
21788
22066
  if (dataLabel && point.visible) {
21789
22067
  _pos = dataLabel._pos;
21790
22068
  if (_pos) {
22069
+
22070
+ // Shorten data labels with ellipsis if they still overflow
22071
+ // after the pie has reached minSize (#223).
22072
+ if (dataLabel.sideOverflow) {
22073
+ dataLabel._attr.width =
22074
+ dataLabel.getBBox().width - dataLabel.sideOverflow;
22075
+ dataLabel.css({
22076
+ width: dataLabel._attr.width + 'px',
22077
+ textOverflow: 'ellipsis'
22078
+ });
22079
+ dataLabel.shortened = true;
22080
+ }
22081
+
21791
22082
  dataLabel.attr(dataLabel._attr);
21792
22083
  dataLabel[dataLabel.moved ? 'animate' : 'attr'](_pos);
21793
22084
  dataLabel.moved = true;
@@ -21797,7 +22088,7 @@
21797
22088
  });
21798
22089
  }
21799
22090
  }
21800
- });
22091
+ }, this);
21801
22092
  };
21802
22093
 
21803
22094
  seriesTypes.pie.prototype.alignDataLabel = noop;
@@ -21930,7 +22221,6 @@
21930
22221
  *
21931
22222
  * License: www.highcharts.com/license
21932
22223
  */
21933
- 'use strict';
21934
22224
  /**
21935
22225
  * Highcharts module to hide overlapping data labels. This module is included in Highcharts.
21936
22226
  */
@@ -21945,7 +22235,7 @@
21945
22235
  function collectAndHide() {
21946
22236
  var labels = [];
21947
22237
 
21948
- each(chart.series, function(series) {
22238
+ each(chart.series || [], function(series) {
21949
22239
  var dlOptions = series.options.dataLabels,
21950
22240
  collections = series.dataLabelCollections || ['dataLabel']; // Range series have two collections
21951
22241
  if ((dlOptions.enabled || series._hasPointLabels) && !dlOptions.allowOverlap && series.visible) { // #3866
@@ -22079,7 +22369,6 @@
22079
22369
  *
22080
22370
  * License: www.highcharts.com/license
22081
22371
  */
22082
- 'use strict';
22083
22372
  var addEvent = H.addEvent,
22084
22373
  Chart = H.Chart,
22085
22374
  createElement = H.createElement,
@@ -22116,15 +22405,10 @@
22116
22405
  chart = series.chart,
22117
22406
  pointer = chart.pointer,
22118
22407
  onMouseOver = function(e) {
22119
- var target = e.target,
22120
- point;
22408
+ var point = pointer.getPointFromEvent(e);
22121
22409
 
22122
- while (target && !point) {
22123
- point = target.point;
22124
- target = target.parentNode;
22125
- }
22126
-
22127
- if (point !== undefined && point !== chart.hoverPoint) { // undefined on graph in scatterchart
22410
+ // undefined on graph in scatterchart
22411
+ if (point !== undefined) {
22128
22412
  point.onMouseOver(e);
22129
22413
  }
22130
22414
  };
@@ -22299,7 +22583,7 @@
22299
22583
 
22300
22584
  setItemEvents: function(item, legendItem, useHTML) {
22301
22585
  var legend = this,
22302
- chart = legend.chart,
22586
+ boxWrapper = legend.chart.renderer.boxWrapper,
22303
22587
  activeClass = 'highcharts-legend-' + (item.series ? 'point' : 'series') + '-active';
22304
22588
 
22305
22589
  // Set the events on the item group, or in case of useHTML, the item itself (#1249)
@@ -22307,7 +22591,7 @@
22307
22591
  item.setState('hover');
22308
22592
 
22309
22593
  // A CSS class to dim or hide other than the hovered series
22310
- chart.seriesGroup.addClass(activeClass);
22594
+ boxWrapper.addClass(activeClass);
22311
22595
 
22312
22596
 
22313
22597
  legendItem.css(legend.options.itemHoverStyle);
@@ -22319,7 +22603,7 @@
22319
22603
 
22320
22604
 
22321
22605
  // A CSS class to dim or hide other than the hovered series
22322
- chart.seriesGroup.removeClass(activeClass);
22606
+ boxWrapper.removeClass(activeClass);
22323
22607
 
22324
22608
  item.setState();
22325
22609
  })
@@ -22501,8 +22785,14 @@
22501
22785
  flipped = panMax < panMin,
22502
22786
  newMin = flipped ? panMax : panMin,
22503
22787
  newMax = flipped ? panMin : panMax,
22504
- distMin = Math.min(extremes.dataMin, extremes.min) - newMin,
22505
- distMax = newMax - Math.max(extremes.dataMax, extremes.max);
22788
+ paddedMin = axis.toValue(
22789
+ axis.toPixels(extremes.min) - axis.minPixelPadding
22790
+ ),
22791
+ paddedMax = axis.toValue(
22792
+ axis.toPixels(extremes.max) + axis.minPixelPadding
22793
+ ),
22794
+ distMin = Math.min(extremes.dataMin, paddedMin) - newMin,
22795
+ distMax = newMax - Math.max(extremes.dataMax, paddedMax);
22506
22796
 
22507
22797
  // Negative distMin and distMax means that we're still inside the
22508
22798
  // data range.
@@ -22572,58 +22862,29 @@
22572
22862
 
22573
22863
  /**
22574
22864
  * Runs on mouse over the point
22575
- *
22865
+ *
22576
22866
  * @param {Object} e The event arguments
22577
- * @param {Boolean} byProximity Falsy for kd points that are closest to the mouse, or to
22578
- * actually hovered points. True for other points in shared tooltip.
22579
22867
  */
22580
- onMouseOver: function(e, byProximity) {
22868
+ onMouseOver: function(e) {
22581
22869
  var point = this,
22582
22870
  series = point.series,
22583
22871
  chart = series.chart,
22584
- tooltip = chart.tooltip,
22585
- hoverPoint = chart.hoverPoint;
22586
-
22587
- if (point.series) { // It may have been destroyed, #4130
22588
- // In shared tooltip, call mouse over when point/series is actually hovered: (#5766)
22589
- if (!byProximity) {
22590
- // set normal state to previous series
22591
- if (hoverPoint && hoverPoint !== point) {
22592
- hoverPoint.onMouseOut();
22593
- }
22594
- if (chart.hoverSeries !== series) {
22595
- series.onMouseOver();
22596
- }
22597
- chart.hoverPoint = point;
22598
- }
22599
-
22600
- // update the tooltip
22601
- if (tooltip && (!tooltip.shared || series.noSharedTooltip)) {
22602
- // hover point only for non shared points: (#5766)
22603
- point.setState('hover');
22604
- tooltip.refresh(point, e);
22605
- } else if (!tooltip) {
22606
- point.setState('hover');
22607
- }
22608
-
22609
- // trigger the event
22610
- point.firePointEvent('mouseOver');
22611
- }
22872
+ pointer = chart.pointer;
22873
+ point.firePointEvent('mouseOver');
22874
+ pointer.runPointActions(e, point);
22612
22875
  },
22613
22876
 
22614
22877
  /**
22615
22878
  * Runs on mouse out from the point
22616
22879
  */
22617
22880
  onMouseOut: function() {
22618
- var chart = this.series.chart,
22619
- hoverPoints = chart.hoverPoints;
22620
-
22621
- this.firePointEvent('mouseOut');
22622
-
22623
- if (!hoverPoints || inArray(this, hoverPoints) === -1) { // #887, #2240
22624
- this.setState();
22625
- chart.hoverPoint = null;
22626
- }
22881
+ var point = this,
22882
+ chart = point.series.chart;
22883
+ point.firePointEvent('mouseOut');
22884
+ each(chart.hoverPoints || [], function(p) {
22885
+ p.setState();
22886
+ });
22887
+ chart.hoverPoints = chart.hoverPoint = null;
22627
22888
  },
22628
22889
 
22629
22890
  /**
@@ -22909,7 +23170,11 @@
22909
23170
  if (series.state !== state) {
22910
23171
 
22911
23172
  // Toggle class names
22912
- each([series.group, series.markerGroup], function(group) {
23173
+ each([
23174
+ series.group,
23175
+ series.markerGroup,
23176
+ series.dataLabelsGroup
23177
+ ], function(group) {
22913
23178
  if (group) {
22914
23179
  // Old state
22915
23180
  if (series.state) {
@@ -22938,8 +23203,16 @@
22938
23203
  attribs = {
22939
23204
  'stroke-width': lineWidth
22940
23205
  };
22941
- // use attr because animate will cause any other animation on the graph to stop
22942
- graph.attr(attribs);
23206
+
23207
+ // Animate the graph stroke-width. By default a quick animation
23208
+ // to hover, slower to un-hover.
23209
+ graph.animate(
23210
+ attribs,
23211
+ pick(
23212
+ series.chart.options.chart.animation,
23213
+ stateOptions[state] && stateOptions[state].animation
23214
+ )
23215
+ );
22943
23216
  while (series['zone-graph-' + i]) {
22944
23217
  series['zone-graph-' + i].attr(attribs);
22945
23218
  i = i + 1;
@@ -23055,34 +23328,76 @@
23055
23328
  *
23056
23329
  * License: www.highcharts.com/license
23057
23330
  */
23058
- 'use strict';
23059
23331
  var Chart = H.Chart,
23060
23332
  each = H.each,
23061
23333
  inArray = H.inArray,
23334
+ isArray = H.isArray,
23062
23335
  isObject = H.isObject,
23063
23336
  pick = H.pick,
23064
23337
  splat = H.splat;
23065
23338
 
23066
23339
  /**
23067
- * Update the chart based on the current chart/document size and options for responsiveness
23340
+ * Update the chart based on the current chart/document size and options for
23341
+ * responsiveness.
23068
23342
  */
23069
23343
  Chart.prototype.setResponsive = function(redraw) {
23070
- var options = this.options.responsive;
23344
+ var options = this.options.responsive,
23345
+ ruleIds = [],
23346
+ currentResponsive = this.currentResponsive,
23347
+ currentRuleIds;
23071
23348
 
23072
23349
  if (options && options.rules) {
23073
23350
  each(options.rules, function(rule) {
23074
- this.matchResponsiveRule(rule, redraw);
23351
+ if (rule._id === undefined) {
23352
+ rule._id = H.uniqueKey();
23353
+ }
23354
+
23355
+ this.matchResponsiveRule(rule, ruleIds, redraw);
23075
23356
  }, this);
23076
23357
  }
23358
+
23359
+ // Merge matching rules
23360
+ var mergedOptions = H.merge.apply(0, H.map(ruleIds, function(ruleId) {
23361
+ return H.find(options.rules, function(rule) {
23362
+ return rule._id === ruleId;
23363
+ }).chartOptions;
23364
+ }));
23365
+
23366
+ // Stringified key for the rules that currently apply.
23367
+ ruleIds = ruleIds.toString() || undefined;
23368
+ currentRuleIds = currentResponsive && currentResponsive.ruleIds;
23369
+
23370
+
23371
+ // Changes in what rules apply
23372
+ if (ruleIds !== currentRuleIds) {
23373
+
23374
+ // Undo previous rules. Before we apply a new set of rules, we need to
23375
+ // roll back completely to base options (#6291).
23376
+ if (currentResponsive) {
23377
+ this.update(currentResponsive.undoOptions, redraw);
23378
+ }
23379
+
23380
+ if (ruleIds) {
23381
+ // Get undo-options for matching rules
23382
+ this.currentResponsive = {
23383
+ ruleIds: ruleIds,
23384
+ mergedOptions: mergedOptions,
23385
+ undoOptions: this.currentOptions(mergedOptions)
23386
+ };
23387
+
23388
+ this.update(mergedOptions, redraw);
23389
+
23390
+ } else {
23391
+ this.currentResponsive = undefined;
23392
+ }
23393
+ }
23077
23394
  };
23078
23395
 
23079
23396
  /**
23080
23397
  * Handle a single responsiveness rule
23081
23398
  */
23082
- Chart.prototype.matchResponsiveRule = function(rule, redraw) {
23083
- var respRules = this.respRules,
23084
- condition = rule.condition,
23085
- matches,
23399
+ Chart.prototype.matchResponsiveRule = function(rule, matches) {
23400
+ var condition = rule.condition,
23086
23401
  fn = condition.callback || function() {
23087
23402
  return this.chartWidth <= pick(condition.maxWidth, Number.MAX_VALUE) &&
23088
23403
  this.chartHeight <= pick(condition.maxHeight, Number.MAX_VALUE) &&
@@ -23090,27 +23405,10 @@
23090
23405
  this.chartHeight >= pick(condition.minHeight, 0);
23091
23406
  };
23092
23407
 
23093
-
23094
- if (rule._id === undefined) {
23095
- rule._id = H.uniqueKey();
23408
+ if (fn.call(this)) {
23409
+ matches.push(rule._id);
23096
23410
  }
23097
- matches = fn.call(this);
23098
-
23099
- // Apply a rule
23100
- if (!respRules[rule._id] && matches) {
23101
-
23102
- // Store the current state of the options
23103
- if (rule.chartOptions) {
23104
- respRules[rule._id] = this.currentOptions(rule.chartOptions);
23105
- this.update(rule.chartOptions, redraw);
23106
- }
23107
23411
 
23108
- // Unapply a rule based on the previous options before the rule
23109
- // was applied
23110
- } else if (respRules[rule._id] && !matches) {
23111
- this.update(respRules[rule._id], redraw);
23112
- delete respRules[rule._id];
23113
- }
23114
23412
  };
23115
23413
 
23116
23414
  /**
@@ -23133,17 +23431,22 @@
23133
23431
  options[key] = splat(options[key]);
23134
23432
 
23135
23433
  ret[key] = [];
23434
+
23435
+ // Iterate over collections like series, xAxis or yAxis and map
23436
+ // the items by index.
23136
23437
  for (i = 0; i < options[key].length; i++) {
23137
- ret[key][i] = {};
23138
- getCurrent(
23139
- options[key][i],
23140
- curr[key][i],
23141
- ret[key][i],
23142
- depth + 1
23143
- );
23438
+ if (curr[key][i]) { // Item exists in current data (#6347)
23439
+ ret[key][i] = {};
23440
+ getCurrent(
23441
+ options[key][i],
23442
+ curr[key][i],
23443
+ ret[key][i],
23444
+ depth + 1
23445
+ );
23446
+ }
23144
23447
  }
23145
23448
  } else if (isObject(options[key])) {
23146
- ret[key] = {};
23449
+ ret[key] = isArray(options[key]) ? [] : {};
23147
23450
  getCurrent(
23148
23451
  options[key],
23149
23452
  curr[key] || {},