highcharts-rails 4.1.7 → 4.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d4a6a629f316d30ec0202c1d30132ca75b330e5c
4
- data.tar.gz: b4159b1bce4ad88d4338a7743b8d659747cddf70
3
+ metadata.gz: b5d2613cbe4c6a3f1071f83ec6fe79c4f94e6d51
4
+ data.tar.gz: a505f22fce9e0075c5012d3f5a73dced8940673d
5
5
  SHA512:
6
- metadata.gz: 4ccdfb6d73da784b1e673e9a6ee7de7fa967cb6320a5926ea682f5d3a84dbd84f77cf764ac3c87886bb9a31ed44fd06d2a1b83f5b0b7b5b2a57c7ec41a9ef36c
7
- data.tar.gz: 86f0408ebf477bcdbd8b921b51e18e53ebe8abbdba1da92aa1ac2dd425e7f2082c4909929aa3a5214f06392bff582cbebcf46480dd2c299d9e82a929d2a356a5
6
+ metadata.gz: 9009c0a9b5bb8bcd42150a35838f3b45ea00917509ae8150b6054004be300301fd3512e3e55b8450217d2b82b8f23290c01a98318ea0a85ab046bf6061cf7201
7
+ data.tar.gz: bd615ab24486525622bb2e0d3038d49359ec7ddb4d2f478dea63f9fe6d6677672be96b0c5f7d7158a7f40e7982a8b35cade4ce80306e14e598bd5ddd875007cc
data/CHANGELOG.markdown CHANGED
@@ -1,3 +1,59 @@
1
+ # 4.1.8 / 2015-08-31
2
+
3
+ * Updated Highcharts to 4.1.8 (2015-08-20)
4
+ * Added experimental support for using HTML in exported charts through the exporting.allowHTML option. Discussed in #2473.
5
+ * Added new option, maxPointWidth, to the column chart type and its derivatives.
6
+ * Add %k, hours with no padding, in dateFormat.
7
+ * Don't cache undefined bounding box key. Closes #4328.
8
+ * Fixed #4448, which causes duplicated event calls for column series.
9
+ * Fixed #1498, minor ticks were missing when using column series.
10
+ * Fixed #1655, where setExtremes event could be called with undefined extremes.
11
+ * Fixed #2775, click on custom button propagated and caused JS errors when destroying chart.
12
+ * Fixed #3379, minPadding and maxPadding was wrong on color axis.
13
+ * Fixed #3737, points within a group were not reversed in a reversed bar chart X axis.
14
+ * Fixed #3879, where linked series didn't inherit initial visibility from a parent.
15
+ * Fixed #3909, HTML data label was invisible after drilling up.
16
+ * Fixed #4149, tooltip went off plot area when data was clipped.
17
+ * Fixed #4189, wrong position of the legend in IE7.
18
+ * Fixed #4219, enconding problem with ellipsis. Better fix for #4079.
19
+ * Fixed #4246, pie slices with null values should not be rendered.
20
+ * Fixed #4313, setting one of the extremes removed both, min and max, axis paddings for bubble series.
21
+ * Fixed #4320, stack items building up and creating memory leak when adding and removing points.
22
+ * Fixed #4333, data label overlapping detection was too aggressive. Don't handle padding when the label doesn't have a border or background.
23
+ * Fixed #4339, touch-dragging in IE11 on a zoom enabled chart caused JS errors.
24
+ * Fixed #4343, axis lines missing when 3D was loaded.
25
+ * Fixed #4347, legend item click of heatmap with data classes should hide items.
26
+ * Fixed #4349, updating point.x prevented point from being hidden from legend.
27
+ * Fixed #4350, pie chart failing with StockChart constructor.
28
+ * Fixed #4356, pointBreak wasn't called for values below the threshold.
29
+ * Fixed #4356, series with null threshold now calls breakPoint correctly
30
+ * Fixed #4359, drilldown pie selected slices had wrong color.
31
+ * Fixed #4360, float error on logarithmic axis label.
32
+ * Fixed #4364, chart click event fired when clicking menu items in the export menu.
33
+ * Fixed #4365, pie chart connectors were not hidden when data labels used HTML and hiding the series.
34
+ * Fixed #4371, where negative Axis offset miscalculated clip-path for series.
35
+ * Fixed #4390, JS error in some cases on updating a series with no data.
36
+ * Fixed #4396, different minSize and maxSize per separate series didn't work.
37
+ * Fixed #4401, better handling categories based on a point.name.
38
+ * Fixed #4410, a regression causing incorrect mouseover events in column charts.
39
+ * Fixed #4411, setting axis.labels.step to 1 didn't result in 1:1 labels.
40
+ * Fixed #4420, generic X axis gridline width with 3d columns.
41
+ * Fixed #4421, overlapping upper data labels on arearange series.
42
+ * Fixed #4430, point color was not set on positive points when negativeColor was set.
43
+ * Fixed #4434, regression causing failure with reversed solid gauge.
44
+ * Fixed #4443, auto rotation was not reset after widening chart when labels used HTML.
45
+ * Fixed #4449, a regression causing wrong alignment on legend items when rtl was combined with useHTML.
46
+ * Fixed #4477, too dense ticks when setting staggerLines, caused browser crash.
47
+ * Fixed #4313, setting one of the extremes removed both, min and max, paddings.
48
+ * Fixed #4351, setSize with standalone adapter didn't resize inner container.
49
+ * Fixed animation on updating map colors.
50
+ * Fixed issue with displayNegative not working with all data. Closes #4419
51
+ * Fixed issue with pie and data labels producing JS error in IE6.
52
+ * Fixed issue with updating mapbubble point to null.
53
+ * Fixed regression with JS error on updating pie slice value to null.
54
+ * Improve logic for pointBreaks, touch #4356
55
+ * Partial fix for #3861, bubble series not working with logarithmic axes. It now displays, but the bubbles are clipped unless the user sets a padding.
56
+
1
57
  # 4.1.7 / 2015-08-31
2
58
 
3
59
  * Updated Highcharts to 4.1.7 (2015-06-26)
data/Rakefile CHANGED
@@ -1 +1,37 @@
1
1
  require 'bundler/gem_tasks'
2
+
3
+ desc "Update to the latest version of Highcharts"
4
+ task :update, :version do |t, args|
5
+ version = args[:version]
6
+ url = "http://code.highcharts.com/zips/Highcharts-#{version}.zip"
7
+ puts "Fetching #{url}"
8
+ `curl -# #{url} -o tmp/#{version}.zip`
9
+ `unzip tmp/#{version}.zip -d tmp/#{version}`
10
+
11
+ mappings = {
12
+ "highcharts.src.js" => "highcharts.js",
13
+ "highcharts-more.src.js" => "highcharts/highcharts-more.js",
14
+ "highcharts-3d.src.js" => "highcharts/highcharts-3d.js",
15
+ "standalone-framework.src.js" => "highcharts/adapters/standalone-framework.js",
16
+ "annotations.src.js" => "highcharts/modules/annotations.js",
17
+ "canvas-tools.src.js" => "highcharts/modules/canvas-tools.js",
18
+ "data.src.js" => "highcharts/modules/data.js",
19
+ "drilldown.src.js" => "highcharts/modules/drilldown.js",
20
+ "exporting.src.js" => "highcharts/modules/exporting.js",
21
+ "funnel.src.js" => "highcharts/modules/funnel.js",
22
+ "heatmap.src.js" => "highcharts/modules/heatmap.js",
23
+ "no-data-to-display.src.js" => "highcharts/modules/no-data-to-display.js",
24
+ "solid-gauge.src.js" => "highcharts/modules/solid-gauge.js",
25
+ "treemap.src.js" => "highcharts/modules/treemap.js",
26
+ "broken-axis.src.js" => "highcharts/modules/broken-axis.js",
27
+ "boost.src.js" => "highcharts/modules/boost.js",
28
+ "offline-exporting.src.js" => "highcharts/modules/offline-exporting.js",
29
+ }
30
+ dest = "app/assets/javascripts/"
31
+ Dir.glob("tmp/#{version}/js/**/*.src.js").each do |file|
32
+ name = File.basename(file)
33
+ FileUtils.cp file, "#{dest}#{mappings[name]}", verbose: true
34
+ end
35
+ FileUtils.cp Dir.glob("tmp/#{version}/js/themes/*.js"), "#{dest}highcharts/themes/", verbose: true
36
+ FileUtils.cp Dir.glob("tmp/#{version}/graphics/*.png"), "app/assets/images/highcharts", verbose: true
37
+ end
@@ -2,7 +2,7 @@
2
2
  // @compilation_level SIMPLE_OPTIMIZATIONS
3
3
 
4
4
  /**
5
- * @license Highcharts JS v4.1.7 (2015-06-26)
5
+ * @license Highcharts JS v4.1.8 (2015-08-20)
6
6
  *
7
7
  * (c) 2009-2014 Torstein Honsi
8
8
  *
@@ -49,14 +49,13 @@ var UNDEFINED,
49
49
  garbageBin,
50
50
  defaultOptions,
51
51
  dateFormat, // function
52
- globalAnimation,
53
52
  pathAnim,
54
53
  timeUnits,
55
54
  noop = function () { return UNDEFINED; },
56
55
  charts = [],
57
56
  chartCount = 0,
58
57
  PRODUCT = 'Highcharts',
59
- VERSION = '4.1.7',
58
+ VERSION = '4.1.8',
60
59
 
61
60
  // some constants for frequently used strings
62
61
  DIV = 'div',
@@ -405,7 +404,7 @@ function getTZOffset(timestamp) {
405
404
  */
406
405
  dateFormat = function (format, timestamp, capitalize) {
407
406
  if (!defined(timestamp) || isNaN(timestamp)) {
408
- return 'Invalid date';
407
+ return defaultOptions.lang.invalidDate || '';
409
408
  }
410
409
  format = pick(format, '%Y-%m-%d %H:%M:%S');
411
410
 
@@ -444,6 +443,7 @@ dateFormat = function (format, timestamp, capitalize) {
444
443
 
445
444
  // Time
446
445
  'H': pad(hours), // Two digits hours in 24h format, 00 through 23
446
+ 'k': hours, // Hours in 24h format, 0 through 23
447
447
  'I': pad((hours % 12) || 12), // Two digits hours in 12h format, 00 through 11
448
448
  'l': (hours % 12) || 12, // Hours in 12h format, 1 through 12
449
449
  'M': pad(date[getMinutes]()), // Two digits minutes, 00 through 59
@@ -710,9 +710,9 @@ function error (code, stop) {
710
710
  * Fix JS round off float errors
711
711
  * @param {Number} num
712
712
  */
713
- function correctFloat(num) {
713
+ function correctFloat(num, prec) {
714
714
  return parseFloat(
715
- num.toPrecision(14)
715
+ num.toPrecision(prec || 14)
716
716
  );
717
717
  }
718
718
 
@@ -723,7 +723,7 @@ function correctFloat(num) {
723
723
  * @param {Object} chart
724
724
  */
725
725
  function setAnimation(animation, chart) {
726
- globalAnimation = pick(animation, chart.animation);
726
+ chart.renderer.globalAnimation = pick(animation, chart.animation);
727
727
  }
728
728
 
729
729
  /**
@@ -1259,6 +1259,7 @@ defaultOptions = {
1259
1259
  'August', 'September', 'October', 'November', 'December'],
1260
1260
  shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
1261
1261
  weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
1262
+ // invalidDate: '',
1262
1263
  decimalPoint: '.',
1263
1264
  numericSymbols: ['k', 'M', 'G', 'T', 'P', 'E'], // SI prefixes used in axis labels
1264
1265
  resetZoom: 'Reset zoom',
@@ -1268,8 +1269,8 @@ defaultOptions = {
1268
1269
  global: {
1269
1270
  useUTC: true,
1270
1271
  //timezoneOffset: 0,
1271
- canvasToolsURL: 'http://code.highcharts.com/4.1.7/modules/canvas-tools.js',
1272
- VMLRadialGradientURL: 'http://code.highcharts.com/4.1.7/gfx/vml-radial-gradient.png'
1272
+ canvasToolsURL: 'http://code.highcharts.com/4.1.8/modules/canvas-tools.js',
1273
+ VMLRadialGradientURL: 'http://code.highcharts.com/4.1.8/gfx/vml-radial-gradient.png'
1273
1274
  },
1274
1275
  chart: {
1275
1276
  //animation: true,
@@ -1796,7 +1797,7 @@ SVGElement.prototype = {
1796
1797
  opacity: 1,
1797
1798
  // For labels, these CSS properties are applied to the <text> node directly
1798
1799
  textProps: ['fontSize', 'fontWeight', 'fontFamily', 'fontStyle', 'color',
1799
- 'lineHeight', 'width', 'textDecoration', 'textShadow'],
1800
+ 'lineHeight', 'width', 'textDecoration', 'textOverflow', 'textShadow'],
1800
1801
 
1801
1802
  /**
1802
1803
  * Initialize the SVG renderer
@@ -1818,7 +1819,7 @@ SVGElement.prototype = {
1818
1819
  * @param {Function} complete Function to perform at the end of animation
1819
1820
  */
1820
1821
  animate: function (params, options, complete) {
1821
- var animOptions = pick(options, globalAnimation, true);
1822
+ var animOptions = pick(options, this.renderer.globalAnimation, true);
1822
1823
  stop(this); // stop regardless of animation actually running, or reverting to .attr (#607)
1823
1824
  if (animOptions) {
1824
1825
  animOptions = merge(animOptions, {}); //#2625
@@ -1827,10 +1828,7 @@ SVGElement.prototype = {
1827
1828
  }
1828
1829
  animate(this, params, animOptions);
1829
1830
  } else {
1830
- this.attr(params);
1831
- if (complete) {
1832
- complete();
1833
- }
1831
+ this.attr(params, null, complete);
1834
1832
  }
1835
1833
  return this;
1836
1834
  },
@@ -1943,9 +1941,9 @@ SVGElement.prototype = {
1943
1941
  * Apply a polyfill to the text-stroke CSS property, by copying the text element
1944
1942
  * and apply strokes to the copy.
1945
1943
  *
1944
+ * Contrast checks at http://jsfiddle.net/highcharts/43soe9m1/2/
1945
+ *
1946
1946
  * docs: update default, document the polyfill and the limitations on hex colors and pixel values, document contrast pseudo-color
1947
- * TODO:
1948
- * - update defaults
1949
1947
  */
1950
1948
  applyTextShadow: function (textShadow) {
1951
1949
  var elem = this.element,
@@ -2033,7 +2031,7 @@ SVGElement.prototype = {
2033
2031
  * @param {Object|String} hash
2034
2032
  * @param {Mixed|Undefined} val
2035
2033
  */
2036
- attr: function (hash, val) {
2034
+ attr: function (hash, val, complete) {
2037
2035
  var key,
2038
2036
  value,
2039
2037
  element = this.element,
@@ -2092,6 +2090,11 @@ SVGElement.prototype = {
2092
2090
 
2093
2091
  }
2094
2092
 
2093
+ // In accordance with animate, run a complete callback
2094
+ if (complete) {
2095
+ complete();
2096
+ }
2097
+
2095
2098
  return ret;
2096
2099
  },
2097
2100
 
@@ -2569,7 +2572,9 @@ SVGElement.prototype = {
2569
2572
  }
2570
2573
 
2571
2574
  // Cache it
2572
- renderer.cache[cacheKey] = bBox;
2575
+ if (cacheKey) {
2576
+ renderer.cache[cacheKey] = bBox;
2577
+ }
2573
2578
  }
2574
2579
  return bBox;
2575
2580
  },
@@ -2578,13 +2583,7 @@ SVGElement.prototype = {
2578
2583
  * Show the element
2579
2584
  */
2580
2585
  show: function (inherit) {
2581
- // IE9-11 doesn't handle visibilty:inherit well, so we remove the attribute instead (#2881)
2582
- if (inherit && this.element.namespaceURI === SVG_NS) {
2583
- this.element.removeAttribute('visibility');
2584
- } else {
2585
- this.attr({ visibility: inherit ? 'inherit' : VISIBLE });
2586
- }
2587
- return this;
2586
+ return this.attr({ visibility: inherit ? 'inherit' : VISIBLE });
2588
2587
  },
2589
2588
 
2590
2589
  /**
@@ -2867,6 +2866,14 @@ SVGElement.prototype = {
2867
2866
  this.colorGradient(value, key, element);
2868
2867
  }
2869
2868
  },
2869
+ visibilitySetter: function (value, key, element) {
2870
+ // IE9-11 doesn't handle visibilty:inherit well, so we remove the attribute instead (#2881, #3909)
2871
+ if (value === 'inherit') {
2872
+ element.removeAttribute(key);
2873
+ } else {
2874
+ element.setAttribute(key, value);
2875
+ }
2876
+ },
2870
2877
  zIndexSetter: function (value, key) {
2871
2878
  var renderer = this.renderer,
2872
2879
  parentGroup = this.parentGroup,
@@ -3491,9 +3498,9 @@ SVGRenderer.prototype = {
3491
3498
  };
3492
3499
 
3493
3500
  return label
3494
- .on('click', function () {
3501
+ .on('click', function (e) {
3495
3502
  if (curState !== 3) {
3496
- callback.call(label);
3503
+ callback.call(label, e);
3497
3504
  }
3498
3505
  })
3499
3506
  .attr(normalState)
@@ -4143,7 +4150,11 @@ SVGRenderer.prototype = {
4143
4150
  wrapper.box = box = shape ?
4144
4151
  renderer.symbol(shape, boxX, boxY, wrapper.width, wrapper.height, deferredAttr) :
4145
4152
  renderer.rect(boxX, boxY, wrapper.width, wrapper.height, 0, deferredAttr[STROKE_WIDTH]);
4146
- box.attr('fill', NONE).add(wrapper);
4153
+
4154
+ if (!box.isImg) { // #4324, fill "none" causes it to be ignored by mouse events in IE
4155
+ box.attr('fill', NONE);
4156
+ }
4157
+ box.add(wrapper);
4147
4158
  }
4148
4159
 
4149
4160
  // apply the box attributes
@@ -4466,7 +4477,7 @@ extend(SVGElement.prototype, {
4466
4477
  rotation = wrapper.rotation,
4467
4478
  baseline,
4468
4479
  textWidth = pInt(wrapper.textWidth),
4469
- currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(',');
4480
+ currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth, wrapper.textAlign].join(',');
4470
4481
 
4471
4482
  if (currentTextTransform !== wrapper.cTT) { // do the calculations and DOM access only if properties changed
4472
4483
 
@@ -4551,6 +4562,7 @@ extend(SVGRenderer.prototype, {
4551
4562
  delete this.bBox;
4552
4563
  }
4553
4564
  element.innerHTML = this.textStr = value;
4565
+ wrapper.htmlUpdateTransform();
4554
4566
  };
4555
4567
 
4556
4568
  // Various setters which rely on update transform
@@ -4638,11 +4650,12 @@ extend(SVGRenderer.prototype, {
4638
4650
  htmlGroupStyle.top = value + PX;
4639
4651
  parentGroup[key] = value;
4640
4652
  parentGroup.doTransform = true;
4641
- },
4642
- visibilitySetter: function (value, key) {
4643
- htmlGroupStyle[key] = value;
4644
4653
  }
4645
4654
  });
4655
+ wrap(parentGroup, 'visibilitySetter', function (proceed, value, key, elem) {
4656
+ proceed.call(this, value, key, elem);
4657
+ htmlGroupStyle[key] = value;
4658
+ });
4646
4659
  });
4647
4660
 
4648
4661
  }
@@ -6045,7 +6058,7 @@ Tick.prototype = {
6045
6058
  gridLineColor = options[gridPrefix + 'LineColor'],
6046
6059
  dashStyle = options[gridPrefix + 'LineDashStyle'],
6047
6060
  tickLength = options[tickPrefix + 'Length'],
6048
- tickWidth = options[tickPrefix + 'Width'] || 0,
6061
+ tickWidth = pick(options[tickPrefix + 'Width'], !type && axis.isXAxis ? 1 : 0), // X axis defaults to 1
6049
6062
  tickColor = options[tickPrefix + 'Color'],
6050
6063
  tickPosition = options[tickPrefix + 'Position'],
6051
6064
  gridLinePath,
@@ -6516,7 +6529,7 @@ Axis.prototype = {
6516
6529
  tickmarkPlacement: 'between', // on or between
6517
6530
  tickPixelInterval: 100,
6518
6531
  tickPosition: 'outside',
6519
- tickWidth: 1,
6532
+ //tickWidth: 1,
6520
6533
  title: {
6521
6534
  //text: null,
6522
6535
  align: 'middle', // low, middle or high
@@ -6548,7 +6561,7 @@ Axis.prototype = {
6548
6561
  maxPadding: 0.05,
6549
6562
  minPadding: 0.05,
6550
6563
  startOnTick: true,
6551
- tickWidth: 0,
6564
+ //tickWidth: 0,
6552
6565
  title: {
6553
6566
  rotation: 270,
6554
6567
  text: 'Values'
@@ -6634,6 +6647,8 @@ Axis.prototype = {
6634
6647
  var isXAxis = userOptions.isX,
6635
6648
  axis = this;
6636
6649
 
6650
+ axis.chart = chart;
6651
+
6637
6652
  // Flag, is the axis horizontal
6638
6653
  axis.horiz = chart.inverted ? !isXAxis : isXAxis;
6639
6654
 
@@ -6664,7 +6679,6 @@ Axis.prototype = {
6664
6679
  //axis.ignoreMinPadding = UNDEFINED; // can be set to true by a column or bar series
6665
6680
  //axis.ignoreMaxPadding = UNDEFINED;
6666
6681
 
6667
- axis.chart = chart;
6668
6682
  axis.reversed = options.reversed;
6669
6683
  axis.zoomEnabled = options.zoomEnabled !== false;
6670
6684
 
@@ -6730,7 +6744,8 @@ Axis.prototype = {
6730
6744
  // Dictionary for stacks
6731
6745
  axis.stacks = {};
6732
6746
  axis.oldStacks = {};
6733
-
6747
+ axis.stacksTouched = 0;
6748
+
6734
6749
  // Min and max in the data
6735
6750
  //axis.dataMin = UNDEFINED,
6736
6751
  //axis.dataMax = UNDEFINED,
@@ -7104,8 +7119,9 @@ Axis.prototype = {
7104
7119
  minorTickPositions = [],
7105
7120
  pos,
7106
7121
  i,
7107
- min = axis.min,
7108
- max = axis.max,
7122
+ pointRangePadding = axis.pointRangePadding || 0,
7123
+ min = axis.min - pointRangePadding, // #1498
7124
+ max = axis.max + pointRangePadding, // #1498
7109
7125
  range = max - min,
7110
7126
  len;
7111
7127
 
@@ -7135,7 +7151,9 @@ Axis.prototype = {
7135
7151
  }
7136
7152
  }
7137
7153
 
7138
- axis.trimTicks(minorTickPositions); // #3652 #3743
7154
+ if(minorTickPositions.length !== 0) { // don't change the extremes, when there is no minor ticks
7155
+ axis.trimTicks(minorTickPositions, options.startOnTick, options.endOnTick); // #3652 #3743 #1498
7156
+ }
7139
7157
  return minorTickPositions;
7140
7158
  },
7141
7159
 
@@ -7300,6 +7318,10 @@ Axis.prototype = {
7300
7318
  axis.minPixelPadding = transA * minPointOffset;
7301
7319
  },
7302
7320
 
7321
+ minFromRange: function () {
7322
+ return this.max - this.range;
7323
+ },
7324
+
7303
7325
  /**
7304
7326
  * Set the tick positions to round values and optionally extend the extremes
7305
7327
  * to the nearest tick
@@ -7343,13 +7365,16 @@ Axis.prototype = {
7343
7365
  if (!secondPass && mathMin(axis.min, pick(axis.dataMin, axis.min)) <= 0) { // #978
7344
7366
  error(10, 1); // Can't plot negative values on log axis
7345
7367
  }
7346
- axis.min = correctFloat(log2lin(axis.min)); // correctFloat cures #934
7347
- axis.max = correctFloat(log2lin(axis.max));
7368
+ // The correctFloat cures #934, float errors on full tens. But it
7369
+ // was too aggressive for #4360 because of conversion back to lin,
7370
+ // therefore use precision 15.
7371
+ axis.min = correctFloat(log2lin(axis.min), 15);
7372
+ axis.max = correctFloat(log2lin(axis.max), 15);
7348
7373
  }
7349
7374
 
7350
7375
  // handle zoomed range
7351
7376
  if (axis.range && defined(axis.max)) {
7352
- axis.userMin = axis.min = mathMax(axis.min, axis.max - axis.range); // #618
7377
+ axis.userMin = axis.min = mathMax(axis.min, axis.minFromRange()); // #618
7353
7378
  axis.userMax = axis.max;
7354
7379
 
7355
7380
  axis.range = null; // don't use it when running setExtremes
@@ -7497,6 +7522,11 @@ Axis.prototype = {
7497
7522
  tickPositions = this.getLinearTickPositions(this.tickInterval, this.min, this.max);
7498
7523
  }
7499
7524
 
7525
+ // Too dense ticks, keep only the first and last (#4477)
7526
+ if (tickPositions.length > this.len) {
7527
+ tickPositions = [tickPositions[0], tickPositions.pop()];
7528
+ }
7529
+
7500
7530
  this.tickPositions = tickPositions;
7501
7531
 
7502
7532
  // Run the tick positioner callback, that allows modifying auto tick positions.
@@ -7653,9 +7683,6 @@ Axis.prototype = {
7653
7683
  */
7654
7684
  setScale: function () {
7655
7685
  var axis = this,
7656
- stacks = axis.stacks,
7657
- type,
7658
- i,
7659
7686
  isDirtyData,
7660
7687
  isDirtyAxisLength;
7661
7688
 
@@ -7680,14 +7707,8 @@ Axis.prototype = {
7680
7707
  if (isDirtyAxisLength || isDirtyData || axis.isLinked || axis.forceRedraw ||
7681
7708
  axis.userMin !== axis.oldUserMin || axis.userMax !== axis.oldUserMax) {
7682
7709
 
7683
- // reset stacks
7684
- if (!axis.isXAxis) {
7685
- for (type in stacks) {
7686
- for (i in stacks[type]) {
7687
- stacks[type][i].total = null;
7688
- stacks[type][i].cum = 0;
7689
- }
7690
- }
7710
+ if (axis.resetStacks) {
7711
+ axis.resetStacks();
7691
7712
  }
7692
7713
 
7693
7714
  axis.forceRedraw = false;
@@ -7706,17 +7727,8 @@ Axis.prototype = {
7706
7727
  if (!axis.isDirty) {
7707
7728
  axis.isDirty = isDirtyAxisLength || axis.min !== axis.oldMin || axis.max !== axis.oldMax;
7708
7729
  }
7709
- } else if (!axis.isXAxis) {
7710
- if (axis.oldStacks) {
7711
- stacks = axis.stacks = axis.oldStacks;
7712
- }
7713
-
7714
- // reset stacks
7715
- for (type in stacks) {
7716
- for (i in stacks[type]) {
7717
- stacks[type][i].cum = stacks[type][i].total;
7718
- }
7719
- }
7730
+ } else if (axis.cleanStacks) {
7731
+ axis.cleanStacks();
7720
7732
  }
7721
7733
  },
7722
7734
 
@@ -7753,10 +7765,6 @@ Axis.prototype = {
7753
7765
  axis.userMax = newMax;
7754
7766
  axis.eventArgs = eventArguments;
7755
7767
 
7756
- // Mark for running afterSetExtremes
7757
- axis.isDirtyExtremes = true;
7758
-
7759
- // redraw
7760
7768
  if (redraw) {
7761
7769
  chart.redraw(animation);
7762
7770
  }
@@ -7770,15 +7778,17 @@ Axis.prototype = {
7770
7778
  zoom: function (newMin, newMax) {
7771
7779
  var dataMin = this.dataMin,
7772
7780
  dataMax = this.dataMax,
7773
- options = this.options;
7781
+ options = this.options,
7782
+ min = mathMin(dataMin, pick(options.min, dataMin)),
7783
+ max = mathMax(dataMax, pick(options.max, dataMax));
7774
7784
 
7775
7785
  // Prevent pinch zooming out of range. Check for defined is for #1946. #1734.
7776
7786
  if (!this.allowZoomOutside) {
7777
- if (defined(dataMin) && newMin <= mathMin(dataMin, pick(options.min, dataMin))) {
7778
- newMin = UNDEFINED;
7787
+ if (defined(dataMin) && newMin <= min) {
7788
+ newMin = min;
7779
7789
  }
7780
- if (defined(dataMax) && newMax >= mathMax(dataMax, pick(options.max, dataMax))) {
7781
- newMax = UNDEFINED;
7790
+ if (defined(dataMax) && newMax >= max) {
7791
+ newMax = max;
7782
7792
  }
7783
7793
  }
7784
7794
 
@@ -7943,7 +7953,7 @@ Axis.prototype = {
7943
7953
  });
7944
7954
  }
7945
7955
 
7946
- } else {
7956
+ } else if (!labelOptions.step) { // #4411
7947
7957
  newTickInterval = getStep(labelMetrics.h);
7948
7958
  }
7949
7959
 
@@ -7977,7 +7987,7 @@ Axis.prototype = {
7977
7987
 
7978
7988
  // Set rotation option unless it is "auto", like in gauges
7979
7989
  if (!isString(labelOptions.rotation)) {
7980
- attr.rotation = labelOptions.rotation;
7990
+ attr.rotation = labelOptions.rotation || 0; // #4443
7981
7991
  }
7982
7992
 
7983
7993
  // Handle auto rotation on horizontal axis
@@ -8199,10 +8209,7 @@ Axis.prototype = {
8199
8209
  );
8200
8210
 
8201
8211
  // Decide the clipping needed to keep the graph inside the plot area and axis lines
8202
- clip = mathFloor(options.lineWidth / 2) * 2;
8203
- if (options.offset) {
8204
- clip = mathMax(0, clip - options.offset);
8205
- }
8212
+ clip = options.offset ? 0 : mathFloor(options.lineWidth / 2) * 2; // #4308, #4371
8206
8213
  clipOffset[invertedSide] = mathMax(clipOffset[invertedSide], clip);
8207
8214
  },
8208
8215
 
@@ -8303,6 +8310,7 @@ Axis.prototype = {
8303
8310
  hasRendered = chart.hasRendered,
8304
8311
  slideInTicks = hasRendered && defined(axis.oldMin) && !isNaN(axis.oldMin),
8305
8312
  showAxis = axis.showAxis,
8313
+ globalAnimation = renderer.globalAnimation,
8306
8314
  from,
8307
8315
  to;
8308
8316
 
@@ -9114,15 +9122,15 @@ Tooltip.prototype = {
9114
9122
  ret = {},
9115
9123
  h = point.h || 0, // #4117
9116
9124
  swapped,
9117
- first = ['y', chart.chartHeight, boxHeight, point.plotY + chart.plotTop],
9118
- second = ['x', chart.chartWidth, boxWidth, point.plotX + chart.plotLeft],
9125
+ first = ['y', chart.chartHeight, boxHeight, point.plotY + chart.plotTop, chart.plotTop, chart.plotTop + chart.plotHeight],
9126
+ second = ['x', chart.chartWidth, boxWidth, point.plotX + chart.plotLeft, chart.plotLeft, chart.plotLeft + chart.plotWidth],
9119
9127
  // The far side is right or bottom
9120
9128
  preferFarSide = pick(point.ttBelow, (chart.inverted && !point.negative) || (!chart.inverted && point.negative)),
9121
9129
  /**
9122
9130
  * Handle the preferred dimension. When the preferred dimension is tooltip
9123
9131
  * on top or bottom of the point, it will look for space there.
9124
9132
  */
9125
- firstDimension = function (dim, outerSize, innerSize, point) {
9133
+ firstDimension = function (dim, outerSize, innerSize, point, min, max) {
9126
9134
  var roomLeft = innerSize < point - distance,
9127
9135
  roomRight = point + distance + innerSize < outerSize,
9128
9136
  alignedLeft = point - distance - innerSize,
@@ -9133,9 +9141,9 @@ Tooltip.prototype = {
9133
9141
  } else if (!preferFarSide && roomLeft) {
9134
9142
  ret[dim] = alignedLeft;
9135
9143
  } else if (roomLeft) {
9136
- ret[dim] = alignedLeft - h < 0 ? alignedLeft : alignedLeft - h;
9144
+ ret[dim] = mathMin(max - innerSize, alignedLeft - h < 0 ? alignedLeft : alignedLeft - h);
9137
9145
  } else if (roomRight) {
9138
- ret[dim] = alignedRight + h + innerSize > outerSize ? alignedRight : alignedRight + h;
9146
+ ret[dim] = mathMax(min, alignedRight + h + innerSize > outerSize ? alignedRight : alignedRight + h);
9139
9147
  } else {
9140
9148
  return false;
9141
9149
  }
@@ -9631,19 +9639,17 @@ Pointer.prototype = {
9631
9639
  tooltip.refresh(kdpoints, e);
9632
9640
  }
9633
9641
 
9634
- // do mouseover on all points except the closest
9642
+ // Do mouseover on all points (#3919, #3985, #4410)
9635
9643
  each(kdpoints, function (point) {
9636
- if (point !== kdpoint) {
9637
- point.onMouseOver(e);
9638
- }
9639
- });
9640
- // #3919, #3985 do mouseover on the closest point last to ensure it is the hoverpoint
9641
- ((hoverSeries && hoverSeries.directTouch && hoverPoint) || kdpoint).onMouseOver(e);
9644
+ point.onMouseOver(e, point !== ((hoverSeries && hoverSeries.directTouch && hoverPoint) || kdpoint));
9645
+ });
9642
9646
  } else {
9643
9647
  if (tooltip) {
9644
9648
  tooltip.refresh(kdpoint, e);
9645
9649
  }
9646
- kdpoint.onMouseOver(e);
9650
+ if(!hoverSeries || !hoverSeries.directTouch) { // #4448
9651
+ kdpoint.onMouseOver(e);
9652
+ }
9647
9653
  }
9648
9654
  this.prevKDPoint = kdpoint;
9649
9655
 
@@ -9805,10 +9811,17 @@ Pointer.prototype = {
9805
9811
  plotHeight = chart.plotHeight,
9806
9812
  clickedInside,
9807
9813
  size,
9814
+ selectionMarker = this.selectionMarker,
9808
9815
  mouseDownX = this.mouseDownX,
9809
9816
  mouseDownY = this.mouseDownY,
9810
9817
  panKey = chartOptions.panKey && e[chartOptions.panKey + 'Key'];
9811
9818
 
9819
+ // If the device supports both touch and mouse (like IE11), and we are touch-dragging
9820
+ // inside the plot area, don't handle the mouse event. #4339.
9821
+ if (selectionMarker && selectionMarker.touch) {
9822
+ return;
9823
+ }
9824
+
9812
9825
  // If the mouse is outside the plot area, adjust to cooordinates
9813
9826
  // inside to prevent the selection marker from going outside
9814
9827
  if (chartX < plotLeft) {
@@ -9834,8 +9847,8 @@ Pointer.prototype = {
9834
9847
 
9835
9848
  // make a selection
9836
9849
  if (chart.hasCartesianSeries && (this.zoomX || this.zoomY) && clickedInside && !panKey) {
9837
- if (!this.selectionMarker) {
9838
- this.selectionMarker = chart.renderer.rect(
9850
+ if (!selectionMarker) {
9851
+ this.selectionMarker = selectionMarker = chart.renderer.rect(
9839
9852
  plotLeft,
9840
9853
  plotTop,
9841
9854
  zoomHor ? 1 : plotWidth,
@@ -9851,24 +9864,24 @@ Pointer.prototype = {
9851
9864
  }
9852
9865
 
9853
9866
  // adjust the width of the selection marker
9854
- if (this.selectionMarker && zoomHor) {
9867
+ if (selectionMarker && zoomHor) {
9855
9868
  size = chartX - mouseDownX;
9856
- this.selectionMarker.attr({
9869
+ selectionMarker.attr({
9857
9870
  width: mathAbs(size),
9858
9871
  x: (size > 0 ? 0 : size) + mouseDownX
9859
9872
  });
9860
9873
  }
9861
9874
  // adjust the height of the selection marker
9862
- if (this.selectionMarker && zoomVert) {
9875
+ if (selectionMarker && zoomVert) {
9863
9876
  size = chartY - mouseDownY;
9864
- this.selectionMarker.attr({
9877
+ selectionMarker.attr({
9865
9878
  height: mathAbs(size),
9866
9879
  y: (size > 0 ? 0 : size) + mouseDownY
9867
9880
  });
9868
9881
  }
9869
9882
 
9870
9883
  // panning
9871
- if (clickedInside && !this.selectionMarker && chartOptions.panning) {
9884
+ if (clickedInside && !selectionMarker && chartOptions.panning) {
9872
9885
  chart.pan(e, chartOptions.panning);
9873
9886
  }
9874
9887
  }
@@ -10294,7 +10307,8 @@ extend(Highcharts.Pointer.prototype, {
10294
10307
  // Set the marker
10295
10308
  if (!selectionMarker) {
10296
10309
  self.selectionMarker = selectionMarker = extend({
10297
- destroy: noop
10310
+ destroy: noop,
10311
+ touch: true
10298
10312
  }, chart.plotBox);
10299
10313
  }
10300
10314
 
@@ -10829,7 +10843,7 @@ Legend.prototype = {
10829
10843
  var chart = this.chart,
10830
10844
  options = this.options,
10831
10845
  // Use the first letter of each alignment option in order to detect the side
10832
- alignment = options.align[0] + options.verticalAlign[0] + options.layout[0];
10846
+ alignment = options.align.charAt(0) + options.verticalAlign.charAt(0) + options.layout.charAt(0); // #4189 - use charAt(x) notation instead of [x] for IE7
10833
10847
 
10834
10848
  if (this.display && !options.floating) {
10835
10849
 
@@ -11517,16 +11531,16 @@ Chart.prototype = {
11517
11531
 
11518
11532
  // redraw axes
11519
11533
  each(axes, function (axis) {
11520
-
11534
+
11521
11535
  // Fire 'afterSetExtremes' only if extremes are set
11522
- if (axis.isDirtyExtremes) { // #821
11523
- axis.isDirtyExtremes = false;
11536
+ var key = axis.min + ',' + axis.max;
11537
+ if (axis.extKey !== key) { // #821, #4452
11538
+ axis.extKey = key;
11524
11539
  afterRedraw.push(function () { // prevent a recursive call to chart.redraw() (#1119)
11525
11540
  fireEvent(axis, 'afterSetExtremes', extend(axis.eventArgs, axis.getExtremes())); // #747, #751
11526
11541
  delete axis.eventArgs;
11527
11542
  });
11528
11543
  }
11529
-
11530
11544
  if (isDirtyBox || hasStackedSeries) {
11531
11545
  axis.redraw();
11532
11546
  }
@@ -11659,26 +11673,6 @@ Chart.prototype = {
11659
11673
  });
11660
11674
  },
11661
11675
 
11662
- /**
11663
- * Generate stacks for each series and calculate stacks total values
11664
- */
11665
- getStacks: function () {
11666
- var chart = this;
11667
-
11668
- // reset stacks for each yAxis
11669
- each(chart.yAxis, function (axis) {
11670
- if (axis.stacks && axis.hasVisibleSeries) {
11671
- axis.oldStacks = axis.stacks;
11672
- }
11673
- });
11674
-
11675
- each(chart.series, function (series) {
11676
- if (series.options.stacking && (series.visible === true || chart.options.chart.ignoreHiddenSeries === false)) {
11677
- series.stackKey = series.type + pick(series.options.stack, '');
11678
- }
11679
- });
11680
- },
11681
-
11682
11676
  /**
11683
11677
  * Show the title and subtitle of the chart
11684
11678
  *
@@ -12047,7 +12041,9 @@ Chart.prototype = {
12047
12041
  var chart = this,
12048
12042
  chartWidth,
12049
12043
  chartHeight,
12050
- fireEndResize;
12044
+ fireEndResize,
12045
+ renderer = chart.renderer,
12046
+ globalAnimation = renderer.globalAnimation;
12051
12047
 
12052
12048
  // Handle the isResizing counter
12053
12049
  chart.isResizing += 1;
@@ -12079,7 +12075,7 @@ Chart.prototype = {
12079
12075
  }, globalAnimation);
12080
12076
 
12081
12077
  chart.setChartSize(true);
12082
- chart.renderer.setSize(chartWidth, chartHeight, animation);
12078
+ renderer.setSize(chartWidth, chartHeight, animation);
12083
12079
 
12084
12080
  // handle axes
12085
12081
  chart.maxTicks = null;
@@ -12366,6 +12362,7 @@ Chart.prototype = {
12366
12362
  if (linkedTo) {
12367
12363
  linkedTo.linkedSeries.push(series);
12368
12364
  series.linkedParent = linkedTo;
12365
+ series.visible = pick(series.options.visible, linkedTo.options.visible, series.visible); // #3879
12369
12366
  }
12370
12367
  }
12371
12368
  });
@@ -12430,7 +12427,10 @@ Chart.prototype = {
12430
12427
  // Legend
12431
12428
  chart.legend = new Legend(chart, options.legend);
12432
12429
 
12433
- chart.getStacks(); // render stacks
12430
+ // Get stacks
12431
+ if (chart.getStacks) {
12432
+ chart.getStacks();
12433
+ }
12434
12434
 
12435
12435
  // Get chart margins
12436
12436
  chart.getMargins(true);
@@ -12895,15 +12895,15 @@ Point.prototype = {
12895
12895
  * Return the configuration hash needed for the data label and tooltip formatters
12896
12896
  */
12897
12897
  getLabelConfig: function () {
12898
- var point = this;
12899
12898
  return {
12900
- x: point.category,
12901
- y: point.y,
12902
- key: point.name || point.category,
12903
- series: point.series,
12904
- point: point,
12905
- percentage: point.percentage,
12906
- total: point.total || point.stackTotal
12899
+ x: this.category,
12900
+ y: this.y,
12901
+ color: this.color,
12902
+ key: this.name || this.category,
12903
+ series: this.series,
12904
+ point: this,
12905
+ percentage: this.percentage,
12906
+ total: this.total || this.stackTotal
12907
12907
  };
12908
12908
  },
12909
12909
 
@@ -13296,7 +13296,9 @@ Series.prototype = {
13296
13296
  * Get the series' color
13297
13297
  */
13298
13298
  getColor: function () {
13299
- if (!this.options.colorByPoint) {
13299
+ if (this.options.colorByPoint) {
13300
+ this.options.color = null; // #4359, selected slice got series.color even when colorByPoint was set.
13301
+ } else {
13300
13302
  this.getCyclic('color', this.options.color || defaultPlotOptions[this.type].color, this.chart.options.colors);
13301
13303
  }
13302
13304
  },
@@ -13412,7 +13414,7 @@ Series.prototype = {
13412
13414
  pt = { series: series };
13413
13415
  series.pointClass.prototype.applyOptions.apply(pt, [data[i]]);
13414
13416
  series.updateParallelArrays(pt, i);
13415
- if (hasCategories && pt.name) {
13417
+ if (hasCategories && defined(pt.name)) { // #4401
13416
13418
  xAxis.names[pt.x] = pt.name; // #2046
13417
13419
  }
13418
13420
  }
@@ -14028,6 +14030,8 @@ Series.prototype = {
14028
14030
  },
14029
14031
  points = series.points || [], // #927
14030
14032
  i,
14033
+ j,
14034
+ threshold,
14031
14035
  point,
14032
14036
  seriesPointAttr = [],
14033
14037
  pointAttr,
@@ -14087,13 +14091,15 @@ Series.prototype = {
14087
14091
  }
14088
14092
 
14089
14093
  if (zones.length) {
14090
- var j = 0,
14091
- threshold = zones[j];
14094
+ j = 0;
14095
+ threshold = zones[j];
14092
14096
  while (point[zoneAxis] >= threshold.value) {
14093
14097
  threshold = zones[++j];
14094
14098
  }
14095
14099
 
14096
- point.color = point.fillColor = threshold.color;
14100
+ if (threshold.color) {
14101
+ point.color = point.fillColor = threshold.color;
14102
+ }
14097
14103
  }
14098
14104
 
14099
14105
  hasPointSpecificOptions = seriesOptions.colorByPoint || point.color; // #868
@@ -14349,7 +14355,6 @@ Series.prototype = {
14349
14355
  attribs;
14350
14356
 
14351
14357
  if (graph) {
14352
- stop(graph); // cancel running animations, #459
14353
14358
  graph.animate({ d: graphPath });
14354
14359
 
14355
14360
  } else if ((lineWidth || fillColor) && graphPath.length) { // #1487
@@ -14388,8 +14393,7 @@ Series.prototype = {
14388
14393
  graph = this.graph,
14389
14394
  area = this.area,
14390
14395
  chartSizeMax = mathMax(chart.chartWidth, chart.chartHeight),
14391
- zoneAxis = this.zoneAxis || 'y',
14392
- axis = this[zoneAxis + 'Axis'],
14396
+ axis = this[(this.zoneAxis || 'y') + 'Axis'],
14393
14397
  extremes,
14394
14398
  reversed = axis.reversed,
14395
14399
  inverted = chart.inverted,
@@ -14399,7 +14403,7 @@ Series.prototype = {
14399
14403
  pxPosMax,
14400
14404
  ignoreZones = false;
14401
14405
 
14402
- if (zones.length && (graph || area)) {
14406
+ if (zones.length && (graph || area) && axis.min !== UNDEFINED) {
14403
14407
  // The use of the Color Threshold assumes there are no gaps
14404
14408
  // so it is safe to hide the original graph and area
14405
14409
  if (graph) {
@@ -14762,7 +14766,7 @@ Series.prototype = {
14762
14766
 
14763
14767
  // Start the recursive build process with a clone of the points array and null points filtered out (#3873)
14764
14768
  function startRecursive() {
14765
- var points = grep(series.points, function (point) {
14769
+ var points = grep(series.points || [], function (point) { // #4390
14766
14770
  return point.y !== null;
14767
14771
  });
14768
14772
 
@@ -14944,6 +14948,26 @@ StackItem.prototype = {
14944
14948
  }
14945
14949
  };
14946
14950
 
14951
+ /**
14952
+ * Generate stacks for each series and calculate stacks total values
14953
+ */
14954
+ Chart.prototype.getStacks = function () {
14955
+ var chart = this;
14956
+
14957
+ // reset stacks for each yAxis
14958
+ each(chart.yAxis, function (axis) {
14959
+ if (axis.stacks && axis.hasVisibleSeries) {
14960
+ axis.oldStacks = axis.stacks;
14961
+ }
14962
+ });
14963
+
14964
+ each(chart.series, function (series) {
14965
+ if (series.options.stacking && (series.visible === true || chart.options.chart.ignoreHiddenSeries === false)) {
14966
+ series.stackKey = series.type + pick(series.options.stack, '');
14967
+ }
14968
+ });
14969
+ };
14970
+
14947
14971
 
14948
14972
  // Stacking methods defined on the Axis prototype
14949
14973
 
@@ -15002,6 +15026,49 @@ Axis.prototype.renderStackTotals = function () {
15002
15026
  }
15003
15027
  };
15004
15028
 
15029
+ /**
15030
+ * Set all the stacks to initial states and destroy unused ones.
15031
+ */
15032
+ Axis.prototype.resetStacks = function () {
15033
+ var stacks = this.stacks,
15034
+ type,
15035
+ i;
15036
+ if (!this.isXAxis) {
15037
+ for (type in stacks) {
15038
+ for (i in stacks[type]) {
15039
+
15040
+ // Clean up memory after point deletion (#1044, #4320)
15041
+ if (stacks[type][i].touched < this.stacksTouched) {
15042
+ stacks[type][i].destroy();
15043
+ delete stacks[type][i];
15044
+
15045
+ // Reset stacks
15046
+ } else {
15047
+ stacks[type][i].total = null;
15048
+ stacks[type][i].cum = 0;
15049
+ }
15050
+ }
15051
+ }
15052
+ }
15053
+ };
15054
+
15055
+ Axis.prototype.cleanStacks = function () {
15056
+ var stacks, type, i;
15057
+
15058
+ if (!this.isXAxis) {
15059
+ if (this.oldStacks) {
15060
+ stacks = this.stacks = this.oldStacks;
15061
+ }
15062
+
15063
+ // reset stacks
15064
+ for (type in stacks) {
15065
+ for (i in stacks[type]) {
15066
+ stacks[type][i].cum = stacks[type][i].total;
15067
+ }
15068
+ }
15069
+ }
15070
+ };
15071
+
15005
15072
 
15006
15073
  // Stacking methods defnied for Series prototype
15007
15074
 
@@ -15038,6 +15105,9 @@ Series.prototype.setStackedPoints = function () {
15038
15105
  x,
15039
15106
  y;
15040
15107
 
15108
+
15109
+ yAxis.stacksTouched += 1;
15110
+
15041
15111
  // loop over the non-null y values and read them into a local array
15042
15112
  for (i = 0; i < yDataLength; i++) {
15043
15113
  x = xData[i];
@@ -15068,7 +15138,7 @@ Series.prototype.setStackedPoints = function () {
15068
15138
  stack = stacks[key][x];
15069
15139
  //stack.points[pointKey] = [stack.cum || stackThreshold];
15070
15140
  stack.points[pointKey] = [pick(stack.cum, stackThreshold)];
15071
-
15141
+ stack.touched = yAxis.stacksTouched;
15072
15142
 
15073
15143
 
15074
15144
  // Add value to the stack total
@@ -15306,11 +15376,9 @@ extend(Point.prototype, {
15306
15376
  if (isObject(options) && !isArray(options)) {
15307
15377
  // Defer the actual redraw until getAttribs has been called (#3260)
15308
15378
  point.redraw = function () {
15309
- if (graphic) {
15379
+ if (graphic && graphic.element) {
15310
15380
  if (options && options.marker && options.marker.symbol) {
15311
15381
  point.graphic = graphic.destroy();
15312
- } else {
15313
- graphic.attr(point.pointAttr[point.state || ''])[point.visible === false ? 'hide' : 'show'](); // #2430
15314
15382
  }
15315
15383
  }
15316
15384
  if (options && options.dataLabels && point.dataLabel) { // #2468
@@ -16157,10 +16225,11 @@ var ColumnSeries = extendClass(Series, {
16157
16225
  groupPadding = categoryWidth * options.groupPadding,
16158
16226
  groupWidth = categoryWidth - 2 * groupPadding,
16159
16227
  pointOffsetWidth = groupWidth / columnCount,
16160
- optionPointWidth = options.pointWidth,
16161
- pointPadding = defined(optionPointWidth) ? (pointOffsetWidth - optionPointWidth) / 2 :
16162
- pointOffsetWidth * options.pointPadding,
16163
- pointWidth = pick(optionPointWidth, pointOffsetWidth - 2 * pointPadding), // exact point width, used in polar charts
16228
+ pointWidth = mathMin(
16229
+ options.maxPointWidth || xAxis.len,
16230
+ pick(options.pointWidth, pointOffsetWidth * (1 - 2 * options.pointPadding))
16231
+ ),
16232
+ pointPadding = (pointOffsetWidth - pointWidth) / 2,
16164
16233
  colIndex = (reversedXAxis ?
16165
16234
  columnCount - (series.columnIndex || 0) : // #1251
16166
16235
  series.columnIndex) || 0,
@@ -16415,7 +16484,7 @@ defaultPlotOptions.scatter = merge(defaultSeriesOptions, {
16415
16484
  enabled: true // Overrides auto-enabling in line series (#3647)
16416
16485
  },
16417
16486
  tooltip: {
16418
- headerFormat: '<span style="color:{series.color}">\u25CF</span> <span style="font-size: 10px;"> {series.name}</span><br/>',
16487
+ headerFormat: '<span style="color:{point.color}">\u25CF</span> <span style="font-size: 10px;"> {series.name}</span><br/>',
16419
16488
  pointFormat: 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>'
16420
16489
  }
16421
16490
  });
@@ -16457,7 +16526,7 @@ defaultPlotOptions.pie = merge(defaultSeriesOptions, {
16457
16526
  distance: 30,
16458
16527
  enabled: true,
16459
16528
  formatter: function () { // #2945
16460
- return this.point.name;
16529
+ return this.y === null ? undefined : this.point.name;
16461
16530
  },
16462
16531
  // softConnector: true,
16463
16532
  x: 0
@@ -16621,11 +16690,6 @@ var PieSeries = {
16621
16690
  fill: 'color'
16622
16691
  },
16623
16692
 
16624
- /**
16625
- * Pies have one color each point
16626
- */
16627
- getColor: noop,
16628
-
16629
16693
  /**
16630
16694
  * Animate the pies in
16631
16695
  */
@@ -16844,47 +16908,48 @@ var PieSeries = {
16844
16908
 
16845
16909
  // draw the slices
16846
16910
  each(series.points, function (point) {
16847
- graphic = point.graphic;
16848
- shapeArgs = point.shapeArgs;
16849
- shadowGroup = point.shadowGroup;
16850
-
16851
- // put the shadow behind all points
16852
- if (shadow && !shadowGroup) {
16853
- shadowGroup = point.shadowGroup = renderer.g('shadow')
16854
- .add(series.shadowGroup);
16855
- }
16911
+ if (point.y !== null) {
16912
+ graphic = point.graphic;
16913
+ shapeArgs = point.shapeArgs;
16914
+ shadowGroup = point.shadowGroup;
16856
16915
 
16857
- // if the point is sliced, use special translation, else use plot area traslation
16858
- groupTranslation = point.sliced ? point.slicedTranslation : {
16859
- translateX: 0,
16860
- translateY: 0
16861
- };
16916
+ // put the shadow behind all points
16917
+ if (shadow && !shadowGroup) {
16918
+ shadowGroup = point.shadowGroup = renderer.g('shadow')
16919
+ .add(series.shadowGroup);
16920
+ }
16862
16921
 
16863
- //group.translate(groupTranslation[0], groupTranslation[1]);
16864
- if (shadowGroup) {
16865
- shadowGroup.attr(groupTranslation);
16866
- }
16922
+ // if the point is sliced, use special translation, else use plot area traslation
16923
+ groupTranslation = point.sliced ? point.slicedTranslation : {
16924
+ translateX: 0,
16925
+ translateY: 0
16926
+ };
16867
16927
 
16868
- // draw the slice
16869
- if (graphic) {
16870
- graphic.animate(extend(shapeArgs, groupTranslation));
16871
- } else {
16872
- attr = { 'stroke-linejoin': 'round' };
16873
- if (!point.visible) {
16874
- attr.visibility = 'hidden';
16928
+ //group.translate(groupTranslation[0], groupTranslation[1]);
16929
+ if (shadowGroup) {
16930
+ shadowGroup.attr(groupTranslation);
16875
16931
  }
16876
16932
 
16877
- point.graphic = graphic = renderer[point.shapeType](shapeArgs)
16878
- .setRadialReference(series.center)
16879
- .attr(
16880
- point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE]
16881
- )
16882
- .attr(attr)
16883
- .attr(groupTranslation)
16884
- .add(series.group)
16885
- .shadow(shadow, shadowGroup);
16886
- }
16933
+ // draw the slice
16934
+ if (graphic) {
16935
+ graphic.animate(extend(shapeArgs, groupTranslation));
16936
+ } else {
16937
+ attr = { 'stroke-linejoin': 'round' };
16938
+ if (!point.visible) {
16939
+ attr.visibility = 'hidden';
16940
+ }
16887
16941
 
16942
+ point.graphic = graphic = renderer[point.shapeType](shapeArgs)
16943
+ .setRadialReference(series.center)
16944
+ .attr(
16945
+ point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE]
16946
+ )
16947
+ .attr(attr)
16948
+ .attr(groupTranslation)
16949
+ .add(series.group)
16950
+ .shadow(shadow, shadowGroup);
16951
+ }
16952
+ }
16888
16953
  });
16889
16954
 
16890
16955
  },
@@ -17680,7 +17745,7 @@ if (seriesTypes.column) {
17680
17745
 
17681
17746
 
17682
17747
  /**
17683
- * Highcharts JS v4.1.7 (2015-06-26)
17748
+ * Highcharts JS v4.1.8 (2015-08-20)
17684
17749
  * Highcharts module to hide overlapping data labels. This module is included by default in Highmaps.
17685
17750
  *
17686
17751
  * (c) 2010-2014 Torstein Honsi
@@ -17702,13 +17767,16 @@ if (seriesTypes.column) {
17702
17767
  var labels = [];
17703
17768
 
17704
17769
  each(chart.series, function (series) {
17705
- var dlOptions = series.options.dataLabels;
17770
+ var dlOptions = series.options.dataLabels,
17771
+ collections = series.dataLabelCollections || ['dataLabel']; // Range series have two collections
17706
17772
  if ((dlOptions.enabled || series._hasPointLabels) && !dlOptions.allowOverlap && series.visible) { // #3866
17707
- each(series.points, function (point) {
17708
- if (point.dataLabel) {
17709
- point.dataLabel.labelrank = pick(point.labelrank, point.shapeArgs && point.shapeArgs.height); // #4118
17710
- labels.push(point.dataLabel);
17711
- }
17773
+ each(collections, function (coll) {
17774
+ each(series.points, function (point) {
17775
+ if (point[coll]) {
17776
+ point[coll].labelrank = pick(point.labelrank, point.shapeArgs && point.shapeArgs.height); // #4118
17777
+ labels.push(point[coll]);
17778
+ }
17779
+ });
17712
17780
  });
17713
17781
  }
17714
17782
  });
@@ -17735,12 +17803,16 @@ if (seriesTypes.column) {
17735
17803
  j,
17736
17804
  label1,
17737
17805
  label2,
17738
- intersectRect = function (pos1, pos2, size1, size2) {
17806
+ isIntersecting,
17807
+ pos1,
17808
+ pos2,
17809
+ padding,
17810
+ intersectRect = function (x1, y1, w1, h1, x2, y2, w2, h2) {
17739
17811
  return !(
17740
- pos2.x > pos1.x + size1.width ||
17741
- pos2.x + size2.width < pos1.x ||
17742
- pos2.y > pos1.y + size1.height ||
17743
- pos2.y + size2.height < pos1.y
17812
+ x2 > x1 + w1 ||
17813
+ x2 + w2 < x1 ||
17814
+ y2 > y1 + h1 ||
17815
+ y2 + h2 < y1
17744
17816
  );
17745
17817
  };
17746
17818
 
@@ -17757,7 +17829,7 @@ if (seriesTypes.column) {
17757
17829
  // will hide the previous one because the previous one always has
17758
17830
  // lower rank.
17759
17831
  labels.sort(function (a, b) {
17760
- return b.labelrank - a.labelrank;
17832
+ return (b.labelrank || 0) - (a.labelrank || 0);
17761
17833
  });
17762
17834
 
17763
17835
  // Detect overlapping labels
@@ -17766,24 +17838,55 @@ if (seriesTypes.column) {
17766
17838
 
17767
17839
  for (j = i + 1; j < len; ++j) {
17768
17840
  label2 = labels[j];
17769
- if (label1 && label2 && label1.placed && label2.placed && label1.newOpacity !== 0 && label2.newOpacity !== 0 &&
17770
- intersectRect(label1.alignAttr, label2.alignAttr, label1, label2)) {
17771
- (label1.labelrank < label2.labelrank ? label1 : label2).newOpacity = 0;
17841
+ if (label1 && label2 && label1.placed && label2.placed && label1.newOpacity !== 0 && label2.newOpacity !== 0) {
17842
+ pos1 = label1.alignAttr;
17843
+ pos2 = label2.alignAttr;
17844
+ padding = 2 * (label1.box ? 0 : label1.padding); // Substract the padding if no background or border (#4333)
17845
+ isIntersecting = intersectRect(
17846
+ pos1.x,
17847
+ pos1.y,
17848
+ label1.width - padding,
17849
+ label1.height - padding,
17850
+ pos2.x,
17851
+ pos2.y,
17852
+ label2.width - padding,
17853
+ label2.height - padding
17854
+ );
17855
+
17856
+ if (isIntersecting) {
17857
+ (label1.labelrank < label2.labelrank ? label1 : label2).newOpacity = 0;
17858
+ }
17772
17859
  }
17773
17860
  }
17774
17861
  }
17775
17862
 
17776
17863
  // Hide or show
17777
- for (i = 0; i < len; i++) {
17778
- label = labels[i];
17864
+ each(labels, function (label) {
17865
+ var complete,
17866
+ newOpacity;
17867
+
17779
17868
  if (label) {
17780
- if (label.oldOpacity !== label.newOpacity && label.placed) {
17781
- label.alignAttr.opacity = label.newOpacity;
17782
- label[label.isOld && label.newOpacity ? 'animate' : 'attr'](label.alignAttr);
17869
+ newOpacity = label.newOpacity;
17870
+
17871
+ if (label.oldOpacity !== newOpacity && label.placed) {
17872
+
17873
+ // Make sure the label is completely hidden to avoid catching clicks (#4362)
17874
+ if (newOpacity) {
17875
+ label.show(true);
17876
+ } else {
17877
+ complete = function () {
17878
+ label.hide();
17879
+ };
17880
+ }
17881
+
17882
+ // Animate or set the opacity
17883
+ label.alignAttr.opacity = newOpacity;
17884
+ label[label.isOld ? 'animate' : 'attr'](label.alignAttr, null, complete);
17885
+
17783
17886
  }
17784
17887
  label.isOld = true;
17785
17888
  }
17786
- }
17889
+ });
17787
17890
  };
17788
17891
 
17789
17892
  }(Highcharts));/**
@@ -18187,8 +18290,12 @@ extend(Point.prototype, {
18187
18290
 
18188
18291
  /**
18189
18292
  * Runs on mouse over the point
18293
+ *
18294
+ * @param {Object} e The event arguments
18295
+ * @param {Boolean} byProximity Falsy for kd points that are closest to the mouse, or to
18296
+ * actually hovered points. True for other points in shared tooltip.
18190
18297
  */
18191
- onMouseOver: function (e) {
18298
+ onMouseOver: function (e, byProximity) {
18192
18299
  var point = this,
18193
18300
  series = point.series,
18194
18301
  chart = series.chart,
@@ -18216,7 +18323,9 @@ extend(Point.prototype, {
18216
18323
 
18217
18324
  // hover this
18218
18325
  point.setState(HOVER_STATE);
18219
- chart.hoverPoint = point;
18326
+ if (!byProximity) {
18327
+ chart.hoverPoint = point;
18328
+ }
18220
18329
  }
18221
18330
  },
18222
18331