highcharts-rails 5.0.7 → 5.0.8

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