highcharts-rails 4.2.5 → 4.2.6

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: 2939d4feed91c6aa1664e68c33af311c52c7bccc
4
- data.tar.gz: cee7f47daf110070a74c538933732d46f056e8ad
3
+ metadata.gz: f77a535a0b707c51c4f72e52ddf05fe4e3b911c3
4
+ data.tar.gz: 6c75ffb6a157954665f1abd492d403529a3b557e
5
5
  SHA512:
6
- metadata.gz: df01b55b3c3e82c15e846e5f7f35fd0cfad67cbdbc67570ae7ebd737ff58d2c4cd19829ce599a08fb142ba771337f914b9079b688eef55dc8ae8e1079675fb1e
7
- data.tar.gz: 54e18726fabf8b724ce627bd2538d4a8c6948d0da8fac305405e32eec19bd32229461455a11cb11a3895c21d1aab8d1602f58199775e45c7ef33cdbc92f45258
6
+ metadata.gz: af2b1ec95756ae60312e86e5b7bbbfd3af55d35e9df0b0a910bfd7e8499d4304e859c7da71f8d2fe2ad7b951c3b28405cb5a31bed565485578050f7294d4dabb
7
+ data.tar.gz: 76c61a2be05c827cf727b7ad23c99672f75d267646c977fc8f441365c6b6489d46d261001424be87d44e7a3e38155c1c7597bf466eff706b925a384bba00ae9b
data/CHANGELOG.markdown CHANGED
@@ -1,3 +1,50 @@
1
+ # 4.2.6 / 2017-01-25
2
+
3
+ * Updated Highcharts to 4.2.6 (2016-08-02)
4
+ * Added crisp correction for crisper treemap points.
5
+ * Added support for animating graphs to the right when updating data or setting axis extremes. Related to #5294.
6
+ * Refactored sideways animation logic for graphs to better reflect shifting data. Closed #5294.
7
+ * Bug fixes
8
+ * Fixed tick animation when showFirstLabel or showLastLabel were set to false.
9
+ * Fixed #2522, point names should fill up categories when X is not set.
10
+ * Fixed #2597, data labels remained visible even though container was hidden.
11
+ * Fixed #3571, treat NaN in data as null.
12
+ * Fixed #4204, hover.brightness wasn't used for positive bars in waterfall.
13
+ * Fixed #4216, connectEnds with null as first point failed.
14
+ * Fixed #5052, wrong placement of ticks on opposite axis on 3D charts.
15
+ * Fixed #5197, JS error on hovering chart after setData before redraw.
16
+ * Fixed #5215, JS error when legend configuration object was set to false.
17
+ * Fixed #5280, stacked area was wrong with non-zero Y axis threshold and data points at 0.
18
+ * Fixed #5287, unsnapped crossshair was hidden after adding points.
19
+ * Fixed #5298, empty cells in Google Spreadsheet made the graph disappear.
20
+ * Fixed #5302, dateFormat didn't handle Date objects like before.
21
+ * Fixed #5310, global stacking affected polygon series.
22
+ * Fixed #5311, JS error when setting an event config to null.
23
+ * Fixed #5322, negative values in pie series was rendered incorrectly.
24
+ * Fixed #5324, calling Renderer.label with a shape of rect failed.
25
+ * Fixed #5332, last axis label was stuck when doing repetetive redraws.
26
+ * Fixed #5337, tooltip for polygon should not behave like scatter points.
27
+ * Fixed #5339, plot area disappeared when categories were too long.
28
+ * Fixed #5348, error in arearange series when trackByArea was false.
29
+ * Fixed #5350, 3D pies failed redraw when animation was off.
30
+ * Fixed #5352, treemap tooltip did not format point value.
31
+ * Fixed #5354, noSharedTooltip was undefined for gauge and solid gauge, which caused errors when shared tooltip was enabled.
32
+ * Fixed #5376, axis title position was wrong with font-size text values.
33
+ * Fixed #5396, drilldown activeDataLabelStyle color contrast did not work.
34
+ * Fixed #5417, regression causing HTML axis labels to misbehave with useHTML and rotation.
35
+ * Fixed #5442, incorrect clipRect counter causing points to disappear on series update.
36
+ * Fixed #5480, axis showed 0k or 0M. Suffix not needed for zero.
37
+ * Fixed #5486, threshold null caused wrong fill on all-negative axis.
38
+ * Fixed #5495, shared tooltips not always working because of rounding error.
39
+ * Fixed #5500, pyramid height caused wrong position.
40
+ * Fixed #5504, exporting module default settings was not compatible with https.
41
+ * Fixed #5513, Chart.setSize required both width and height to be set.
42
+ * Fixed #5519, issues with setting null colors in drilldown.
43
+ * Fixed #5522, 3D charts scale differently first time versus subsequent redraws.
44
+ * Fixed #5523, marker radius was incorrect when values were of type string.
45
+ * Fixed issues with PNG/JEPG in IE and Edge in offline exporting, ref #5410.
46
+ * Fixed issue #5410, offline exporting in IE/Edge failed with embedded images for PNG/JPEG.
47
+
1
48
  # 4.2.5 / 2016-05-06
2
49
 
3
50
  * Updated Highcharts to 4.2.5 (2016-05-06)
@@ -2,7 +2,7 @@
2
2
  // @compilation_level SIMPLE_OPTIMIZATIONS
3
3
 
4
4
  /**
5
- * @license Highcharts JS v4.2.5 (2016-05-06)
5
+ * @license Highcharts JS v4.2.6 (2016-08-02)
6
6
  *
7
7
  * (c) 2009-2016 Torstein Honsi
8
8
  *
@@ -59,7 +59,7 @@
59
59
  charts = [],
60
60
  chartCount = 0,
61
61
  PRODUCT = 'Highcharts',
62
- VERSION = '4.2.5',
62
+ VERSION = '4.2.6',
63
63
 
64
64
  // some constants for frequently used strings
65
65
  DIV = 'div',
@@ -304,57 +304,83 @@
304
304
  */
305
305
  initPath: function (elem, fromD, toD) {
306
306
  fromD = fromD || '';
307
- var shift = elem.shift,
307
+ var shift,
308
+ startX = elem.startX,
309
+ endX = elem.endX,
308
310
  bezier = fromD.indexOf('C') > -1,
309
311
  numParams = bezier ? 7 : 3,
310
- endLength,
312
+ fullLength,
311
313
  slice,
312
314
  i,
313
315
  start = fromD.split(' '),
314
- end = [].concat(toD), // copy
316
+ end = toD.slice(), // copy
315
317
  isArea = elem.isArea,
316
318
  positionFactor = isArea ? 2 : 1,
317
- sixify = function (arr) { // in splines make move points have six parameters like bezier curves
318
- i = arr.length;
319
- while (i--) {
320
- if (arr[i] === M || arr[i] === L) {
321
- arr.splice(i + 1, 0, arr[i + 1], arr[i + 2], arr[i + 1], arr[i + 2]);
322
- }
319
+ reverse;
320
+
321
+ /**
322
+ * In splines make move points have six parameters like bezier curves
323
+ */
324
+ function sixify(arr) {
325
+ i = arr.length;
326
+ while (i--) {
327
+ if (arr[i] === M || arr[i] === L) {
328
+ arr.splice(i + 1, 0, arr[i + 1], arr[i + 2], arr[i + 1], arr[i + 2]);
323
329
  }
324
- };
330
+ }
331
+ }
325
332
 
326
- if (bezier) {
327
- sixify(start);
328
- sixify(end);
333
+ /**
334
+ * Insert an array at the given position of another array
335
+ */
336
+ function insertSlice(arr, subArr, index) {
337
+ [].splice.apply(
338
+ arr,
339
+ [index, 0].concat(subArr)
340
+ );
329
341
  }
330
342
 
331
- // If shifting points, prepend a dummy point to the end path. For areas,
332
- // prepend both at the beginning and end of the path.
333
- if (shift <= end.length / numParams && start.length === end.length) {
334
- while (shift--) {
335
- end = end.slice(0, numParams).concat(end);
343
+ /**
344
+ * If shifting points, prepend a dummy point to the end path.
345
+ */
346
+ function prepend(arr, other) {
347
+ while (arr.length < fullLength) {
348
+
349
+ // Move to, line to or curve to?
350
+ arr[0] = other[fullLength - arr.length];
351
+
352
+ // Prepend a copy of the first point
353
+ insertSlice(arr, arr.slice(0, numParams), 0);
354
+
355
+ // For areas, the bottom path goes back again to the left, so we need
356
+ // to append a copy of the last point.
336
357
  if (isArea) {
337
- end = end.concat(end.slice(end.length - numParams));
358
+ insertSlice(arr, arr.slice(arr.length - numParams), arr.length);
359
+ i--;
338
360
  }
339
361
  }
362
+ arr[0] = 'M';
340
363
  }
341
- elem.shift = 0; // reset for following animations
342
364
 
343
-
344
- // Copy and append last point until the length matches the end length
345
- if (start.length) {
346
- endLength = end.length;
347
- while (start.length < endLength) {
365
+ /**
366
+ * Copy and append last point until the length matches the end length
367
+ */
368
+ function append(arr, other) {
369
+ var i = (fullLength - arr.length) / numParams;
370
+ while (i > 0 && i--) {
348
371
 
349
372
  // Pull out the slice that is going to be appended or inserted. In a line graph,
350
373
  // the positionFactor is 1, and the last point is sliced out. In an area graph,
351
374
  // the positionFactor is 2, causing the middle two points to be sliced out, since
352
375
  // an area path starts at left, follows the upper path then turns and follows the
353
376
  // bottom back.
354
- slice = start.slice().splice(
355
- (start.length / positionFactor) - numParams,
377
+ slice = arr.slice().splice(
378
+ (arr.length / positionFactor) - numParams,
356
379
  numParams * positionFactor
357
380
  );
381
+
382
+ // Move to, line to or curve to?
383
+ slice[0] = other[fullLength - numParams - (i * numParams)];
358
384
 
359
385
  // Disable first control point
360
386
  if (bezier) {
@@ -363,11 +389,49 @@
363
389
  }
364
390
 
365
391
  // Now insert the slice, either in the middle (for areas) or at the end (for lines)
366
- [].splice.apply(
367
- start,
368
- [(start.length / positionFactor), 0].concat(slice)
369
- );
392
+ insertSlice(arr, slice, arr.length / positionFactor);
393
+
394
+ if (isArea) {
395
+ i--;
396
+ }
397
+ }
398
+ }
399
+
400
+ if (bezier) {
401
+ sixify(start);
402
+ sixify(end);
403
+ }
370
404
 
405
+ // For sideways animation, find out how much we need to shift to get the start path Xs
406
+ // to match the end path Xs.
407
+ if (startX && endX) {
408
+ for (i = 0; i < startX.length; i++) {
409
+ if (startX[i] === endX[0]) { // Moving left, new points coming in on right
410
+ shift = i;
411
+ break;
412
+ } else if (startX[0] === endX[endX.length - startX.length + i]) { // Moving right
413
+ shift = i;
414
+ reverse = true;
415
+ break;
416
+ }
417
+ }
418
+ if (shift === undefined) {
419
+ start = [];
420
+ }
421
+ }
422
+
423
+ if (start.length && Highcharts.isNumber(shift)) {
424
+
425
+ // The common target length for the start and end array, where both
426
+ // arrays are padded in opposite ends
427
+ fullLength = end.length + shift * positionFactor * numParams;
428
+
429
+ if (!reverse) {
430
+ prepend(end, start);
431
+ append(start, end);
432
+ } else {
433
+ prepend(start, end);
434
+ append(end, start);
371
435
  }
372
436
  }
373
437
 
@@ -463,20 +527,22 @@
463
527
  }
464
528
 
465
529
  /**
466
- * Check for object
530
+ * Check for array
467
531
  * @param {Object} obj
468
532
  */
469
- function isObject(obj) {
470
- return obj && typeof obj === 'object';
533
+ function isArray(obj) {
534
+ return Object.prototype.toString.call(obj) === '[object Array]';
471
535
  }
472
536
 
473
537
  /**
474
- * Check for array
538
+ * Check for object
475
539
  * @param {Object} obj
540
+ * @param {Boolean} strict Also checks that the object is not an array
476
541
  */
477
- function isArray(obj) {
478
- return Object.prototype.toString.call(obj) === '[object Array]';
479
- }
542
+ var isObject = Highcharts.isObject = function (obj, strict) {
543
+ //debugger;
544
+ return obj && typeof obj === 'object' && (!strict || !isArray(obj));
545
+ };
480
546
 
481
547
  /**
482
548
  * Check for number
@@ -676,7 +742,7 @@
676
742
  * @param {Boolean} capitalize
677
743
  */
678
744
  dateFormat = function (format, timestamp, capitalize) {
679
- if (!isNumber(timestamp)) {
745
+ if (!defined(timestamp) || isNaN(timestamp)) {
680
746
  return defaultOptions.lang.invalidDate || '';
681
747
  }
682
748
  format = pick(format, '%Y-%m-%d %H:%M:%S');
@@ -1317,7 +1383,7 @@
1317
1383
  fn = events[i];
1318
1384
 
1319
1385
  // If the event handler return false, prevent the default handler from executing
1320
- if (fn.call(el, eventArguments) === false) {
1386
+ if (fn && fn.call(el, eventArguments) === false) {
1321
1387
  eventArguments.preventDefault();
1322
1388
  }
1323
1389
  }
@@ -1535,7 +1601,7 @@
1535
1601
  useUTC: true,
1536
1602
  //timezoneOffset: 0,
1537
1603
  canvasToolsURL: 'http://code.highcharts.com/modules/canvas-tools.js',
1538
- VMLRadialGradientURL: 'http://code.highcharts.com/4.2.5/gfx/vml-radial-gradient.png'
1604
+ VMLRadialGradientURL: 'http://code.highcharts.com/4.2.6/gfx/vml-radial-gradient.png'
1539
1605
  },
1540
1606
  chart: {
1541
1607
  //animation: true,
@@ -1581,7 +1647,9 @@
1581
1647
  y: 10
1582
1648
  }
1583
1649
  // relativeTo: 'plot'
1584
- }
1650
+ },
1651
+ width: null,
1652
+ height: null
1585
1653
  },
1586
1654
  title: {
1587
1655
  text: 'Chart title',
@@ -3513,7 +3581,7 @@
3513
3581
 
3514
3582
  // Skip tspans, add text directly to text node. The forceTSpan is a hook
3515
3583
  // used in text outline hack.
3516
- if (!hasMarkup && !textShadow && !ellipsis && textStr.indexOf(' ') === -1) {
3584
+ if (!hasMarkup && !textShadow && !ellipsis && !width && textStr.indexOf(' ') === -1) {
3517
3585
  textNode.appendChild(doc.createTextNode(unescapeAngleBrackets(textStr)));
3518
3586
 
3519
3587
  // Complex strings, add more logic
@@ -4526,8 +4594,7 @@
4526
4594
  // create the border box if it is not already present
4527
4595
  boxX = crispAdjust;
4528
4596
  boxY = (baseline ? -baselineOffset : 0) + crispAdjust;
4529
-
4530
- wrapper.box = box = shape ?
4597
+ wrapper.box = box = renderer.symbols[shape] ? // Symbol definition exists (#5324)
4531
4598
  renderer.symbol(shape, boxX, boxY, wrapper.width, wrapper.height, deferredAttr) :
4532
4599
  renderer.rect(boxX, boxY, wrapper.width, wrapper.height, 0, deferredAttr[STROKE_WIDTH]);
4533
4600
 
@@ -4875,6 +4942,12 @@
4875
4942
  wrapper.setSpanRotation(rotation, alignCorrection, baseline);
4876
4943
  }
4877
4944
 
4945
+ // Reset multiline/ellipsis in order to read width (#4928, #5417)
4946
+ css(elem, {
4947
+ width: '',
4948
+ whiteSpace: whiteSpace || 'nowrap'
4949
+ });
4950
+
4878
4951
  // Update textWidth
4879
4952
  if (elem.offsetWidth > textWidth && /[ \-]/.test(elem.textContent || elem.innerText)) { // #983, #1254
4880
4953
  css(elem, {
@@ -4882,17 +4955,10 @@
4882
4955
  display: 'block',
4883
4956
  whiteSpace: whiteSpace || 'normal' // #3331
4884
4957
  });
4885
- wrapper.hasTextWidth = true;
4886
- } else if (wrapper.hasTextWidth) { // #4928
4887
- css(elem, {
4888
- width: '',
4889
- display: '',
4890
- whiteSpace: whiteSpace || 'nowrap'
4891
- });
4892
- wrapper.hasTextWidth = false;
4893
4958
  }
4894
4959
 
4895
- wrapper.getSpanCorrection(wrapper.hasTextWidth ? textWidth : elem.offsetWidth, baseline, alignCorrection, rotation, align);
4960
+
4961
+ wrapper.getSpanCorrection(elem.offsetWidth, baseline, alignCorrection, rotation, align);
4896
4962
  }
4897
4963
 
4898
4964
  // apply position with correction
@@ -6609,10 +6675,11 @@
6609
6675
  if (show && isNumber(xy.y)) {
6610
6676
  xy.opacity = opacity;
6611
6677
  label[tick.isNew ? 'attr' : 'animate'](xy);
6612
- tick.isNew = false;
6613
6678
  } else {
6679
+ stop(label); // #5332
6614
6680
  label.attr('y', -9999); // #1338
6615
6681
  }
6682
+ tick.isNew = false;
6616
6683
  }
6617
6684
  },
6618
6685
 
@@ -7299,7 +7366,7 @@
7299
7366
  // logic to the numberFormatter and enable it by a parameter.
7300
7367
  while (i-- && ret === UNDEFINED) {
7301
7368
  multi = Math.pow(1000, i + 1);
7302
- if (numericSymbolDetector >= multi && (value * 10) % multi === 0 && numericSymbols[i] !== null) {
7369
+ if (numericSymbolDetector >= multi && (value * 10) % multi === 0 && numericSymbols[i] !== null && value !== 0) { // #5480
7303
7370
  ret = Highcharts.numberFormat(value / multi, -1) + numericSymbols[i];
7304
7371
  }
7305
7372
  }
@@ -7702,14 +7769,19 @@
7702
7769
  */
7703
7770
  getClosest: function () {
7704
7771
  var ret;
7705
- each(this.series, function (series) {
7706
- var seriesClosest = series.closestPointRange;
7707
- if (!series.noSharedTooltip && defined(seriesClosest)) {
7708
- ret = defined(ret) ?
7709
- mathMin(ret, seriesClosest) :
7710
- seriesClosest;
7711
- }
7712
- });
7772
+
7773
+ if (this.categories) {
7774
+ ret = 1;
7775
+ } else {
7776
+ each(this.series, function (series) {
7777
+ var seriesClosest = series.closestPointRange;
7778
+ if (!series.noSharedTooltip && defined(seriesClosest)) {
7779
+ ret = defined(ret) ?
7780
+ mathMin(ret, seriesClosest) :
7781
+ seriesClosest;
7782
+ }
7783
+ });
7784
+ }
7713
7785
  return ret;
7714
7786
  },
7715
7787
 
@@ -8410,10 +8482,8 @@
8410
8482
  realMin = isLog ? lin2log(axis.min) : axis.min,
8411
8483
  realMax = isLog ? lin2log(axis.max) : axis.max;
8412
8484
 
8413
- // With a threshold of null, make the columns/areas rise from the top or bottom
8414
- // depending on the value, assuming an actual threshold of 0 (#4233).
8415
8485
  if (threshold === null) {
8416
- threshold = realMax < 0 ? realMax : realMin;
8486
+ threshold = realMin;
8417
8487
  } else if (realMin > threshold) {
8418
8488
  threshold = realMin;
8419
8489
  } else if (realMax < threshold) {
@@ -8885,7 +8955,7 @@
8885
8955
  offset = this.offset,
8886
8956
  xOption = axisTitleOptions.x || 0,
8887
8957
  yOption = axisTitleOptions.y || 0,
8888
- fontSize = pInt(axisTitleOptions.style.fontSize || 12),
8958
+ fontSize = this.chart.renderer.fontMetrics(axisTitleOptions.style.fontSize).f,
8889
8959
 
8890
8960
  // the position in the length direction of the axis
8891
8961
  alongAxis = {
@@ -9160,17 +9230,15 @@
9160
9230
  plotLinesAndBands[i].destroy();
9161
9231
  }
9162
9232
 
9163
- // Destroy local variables
9164
- each(['stackTotalGroup', 'axisLine', 'axisTitle', 'axisGroup', 'cross', 'gridGroup', 'labelGroup'], function (prop) {
9233
+ // Destroy properties
9234
+ each(['stackTotalGroup', 'axisLine', 'axisTitle', 'axisGroup', 'gridGroup', 'labelGroup', 'cross'], function (prop) {
9165
9235
  if (axis[prop]) {
9166
9236
  axis[prop] = axis[prop].destroy();
9167
9237
  }
9168
9238
  });
9169
9239
 
9170
- // Destroy crosshair
9171
- if (this.cross) {
9172
- this.cross.destroy();
9173
- }
9240
+
9241
+ this._addedPlotLB = this.chart._labelPanes = this.ordinalSlope = undefined; // #1611, #2887, #4314, #5316
9174
9242
  },
9175
9243
 
9176
9244
  /**
@@ -9188,6 +9256,12 @@
9188
9256
  categorized,
9189
9257
  strokeWidth;
9190
9258
 
9259
+ // Use last available event when updating non-snapped crosshairs without
9260
+ // mouse interaction (#5287)
9261
+ if (!e) {
9262
+ e = this.cross && this.cross.e;
9263
+ }
9264
+
9191
9265
  if (
9192
9266
  // Disabled in options
9193
9267
  !this.crosshair ||
@@ -9195,7 +9269,6 @@
9195
9269
  ((defined(point) || !pick(options.snap, true)) === false)
9196
9270
  ) {
9197
9271
  this.hideCrosshair();
9198
-
9199
9272
  } else {
9200
9273
 
9201
9274
  // Get the path
@@ -9239,7 +9312,7 @@
9239
9312
  }
9240
9313
  this.cross = this.chart.renderer.path(path).attr(attribs).add();
9241
9314
  }
9242
-
9315
+ this.cross.e = e;
9243
9316
  }
9244
9317
 
9245
9318
  },
@@ -9616,7 +9689,7 @@
9616
9689
  .css(style)
9617
9690
  .css({ padding: 0 }) // Remove it from VML, the padding is applied as an attribute instead (#1117)
9618
9691
  .add()
9619
- .attr({ y: -9999 }); // #2301, #2657
9692
+ .attr({ y: -9e9 }); // #2301, #2657, #3532
9620
9693
 
9621
9694
  // When using canVG the shadow shows up as a gray circle
9622
9695
  // even if the tooltip is hidden.
@@ -10055,18 +10128,18 @@
10055
10128
  * Format the footer/header of the tooltip
10056
10129
  * #3397: abstraction to enable formatting of footer and header
10057
10130
  */
10058
- tooltipFooterHeaderFormatter: function (point, isFooter) {
10131
+ tooltipFooterHeaderFormatter: function (labelConfig, isFooter) {
10059
10132
  var footOrHead = isFooter ? 'footer' : 'header',
10060
- series = point.series,
10133
+ series = labelConfig.series,
10061
10134
  tooltipOptions = series.tooltipOptions,
10062
10135
  xDateFormat = tooltipOptions.xDateFormat,
10063
10136
  xAxis = series.xAxis,
10064
- isDateTime = xAxis && xAxis.options.type === 'datetime' && isNumber(point.key),
10137
+ isDateTime = xAxis && xAxis.options.type === 'datetime' && isNumber(labelConfig.key),
10065
10138
  formatString = tooltipOptions[footOrHead + 'Format'];
10066
10139
 
10067
10140
  // Guess the best date format based on the closest point distance (#568, #3418)
10068
10141
  if (isDateTime && !xDateFormat) {
10069
- xDateFormat = this.getXDateFormat(point, tooltipOptions, xAxis);
10142
+ xDateFormat = this.getXDateFormat(labelConfig, tooltipOptions, xAxis);
10070
10143
  }
10071
10144
 
10072
10145
  // Insert the footer date format if any
@@ -10075,7 +10148,7 @@
10075
10148
  }
10076
10149
 
10077
10150
  return format(formatString, {
10078
- point: point,
10151
+ point: labelConfig,
10079
10152
  series: series
10080
10153
  });
10081
10154
  },
@@ -10255,7 +10328,7 @@
10255
10328
  directTouch = !shared && s.directTouch;
10256
10329
  if (s.visible && !noSharedTooltip && !directTouch && pick(s.options.enableMouseTracking, true)) { // #3821
10257
10330
  kdpointT = s.searchPoint(e, !noSharedTooltip && s.kdDimensions === 1); // #3828
10258
- if (kdpointT) {
10331
+ if (kdpointT && kdpointT.series) { // Point.series becomes null when reset and before redraw (#5197)
10259
10332
  kdpoints.push(kdpointT);
10260
10333
  }
10261
10334
  }
@@ -10376,13 +10449,10 @@
10376
10449
  if (hoverPoint) { // #2500
10377
10450
  hoverPoint.setState(hoverPoint.state, true);
10378
10451
  each(chart.axes, function (axis) {
10379
- if (pick(axis.crosshair && axis.crosshair.snap, true)) {
10452
+ if (axis.crosshair) {
10380
10453
  axis.drawCrosshair(null, hoverPoint);
10381
- } else {
10382
- axis.hideCrosshair();
10383
10454
  }
10384
10455
  });
10385
-
10386
10456
  }
10387
10457
  }
10388
10458
 
@@ -10417,8 +10487,7 @@
10417
10487
  axis.hideCrosshair();
10418
10488
  });
10419
10489
 
10420
- pointer.hoverX = chart.hoverPoints = chart.hoverPoint = null;
10421
-
10490
+ pointer.hoverX = pointer.prevKDPoint = chart.hoverPoints = chart.hoverPoint = null;
10422
10491
  }
10423
10492
  },
10424
10493
 
@@ -11535,7 +11604,7 @@
11535
11604
  // Use the first letter of each alignment option in order to detect the side
11536
11605
  alignment = options.align.charAt(0) + options.verticalAlign.charAt(0) + options.layout.charAt(0); // #4189 - use charAt(x) notation instead of [x] for IE7
11537
11606
 
11538
- if (this.display && !options.floating) {
11607
+ if (!options.floating) {
11539
11608
 
11540
11609
  each([
11541
11610
  /(lth|ct|rth)/,
@@ -12666,7 +12735,9 @@
12666
12735
  }
12667
12736
 
12668
12737
  // Adjust for legend
12669
- chart.legend.adjustMargins(margin, spacing);
12738
+ if (chart.legend.display) {
12739
+ chart.legend.adjustMargins(margin, spacing);
12740
+ }
12670
12741
 
12671
12742
  // adjust for scroller
12672
12743
  if (chart.extraBottomMargin) {
@@ -12713,20 +12784,20 @@
12713
12784
  var chart = this,
12714
12785
  optionsChart = chart.options.chart,
12715
12786
  renderTo = chart.renderTo,
12787
+ hasUserWidth = defined(optionsChart.width),
12716
12788
  width = optionsChart.width || getStyle(renderTo, 'width'),
12717
12789
  height = optionsChart.height || getStyle(renderTo, 'height'),
12718
12790
  target = e ? e.target : win;
12719
12791
 
12720
12792
  // Width and height checks for display:none. Target is doc in IE8 and Opera,
12721
12793
  // win in Firefox, Chrome and IE9.
12722
- if (!chart.hasUserSize && !chart.isPrinting && width && height && (target === win || target === doc)) { // #1093
12794
+ if (!hasUserWidth && !chart.isPrinting && width && height && (target === win || target === doc)) { // #1093
12723
12795
  if (width !== chart.containerWidth || height !== chart.containerHeight) {
12724
12796
  clearTimeout(chart.reflowTimeout);
12725
12797
  // When called from window.resize, e is set, else it's called directly (#2224)
12726
12798
  chart.reflowTimeout = syncTimeout(function () {
12727
12799
  if (chart.container) { // It may have been destroyed in the meantime (#1257)
12728
- chart.setSize(width, height, false);
12729
- chart.hasUserSize = null;
12800
+ chart.setSize(undefined, undefined, false);
12730
12801
  }
12731
12802
  }, e ? 100 : 0);
12732
12803
  }
@@ -12759,8 +12830,6 @@
12759
12830
  */
12760
12831
  setSize: function (width, height, animation) {
12761
12832
  var chart = this,
12762
- chartWidth,
12763
- chartHeight,
12764
12833
  renderer = chart.renderer,
12765
12834
  globalAnimation;
12766
12835
 
@@ -12772,23 +12841,23 @@
12772
12841
 
12773
12842
  chart.oldChartHeight = chart.chartHeight;
12774
12843
  chart.oldChartWidth = chart.chartWidth;
12775
- if (defined(width)) {
12776
- chart.chartWidth = chartWidth = mathMax(0, mathRound(width));
12777
- chart.hasUserSize = !!chartWidth;
12844
+ if (width !== undefined) {
12845
+ chart.options.chart.width = width;
12778
12846
  }
12779
- if (defined(height)) {
12780
- chart.chartHeight = chartHeight = mathMax(0, mathRound(height));
12847
+ if (height !== undefined) {
12848
+ chart.options.chart.height = height;
12781
12849
  }
12850
+ chart.getChartSize();
12782
12851
 
12783
12852
  // Resize the container with the global animation applied if enabled (#2503)
12784
12853
  globalAnimation = renderer.globalAnimation;
12785
12854
  (globalAnimation ? animate : css)(chart.container, {
12786
- width: chartWidth + PX,
12787
- height: chartHeight + PX
12855
+ width: chart.chartWidth + PX,
12856
+ height: chart.chartHeight + PX
12788
12857
  }, globalAnimation);
12789
12858
 
12790
12859
  chart.setChartSize(true);
12791
- renderer.setSize(chartWidth, chartHeight, animation);
12860
+ renderer.setSize(chart.chartWidth, chart.chartHeight, animation);
12792
12861
 
12793
12862
  // handle axes
12794
12863
  chart.maxTicks = null;
@@ -13509,12 +13578,21 @@
13509
13578
  if (pointValKey) {
13510
13579
  point.y = point[pointValKey];
13511
13580
  }
13512
- point.isNull = point.x === null || point.y === null;
13581
+ point.isNull = point.x === null || !isNumber(point.y, true); // #3571, check for NaN
13513
13582
 
13514
13583
  // If no x is set by now, get auto incremented value. All points must have an
13515
13584
  // x value, however the y value can be null to create a gap in the series
13516
13585
  if (point.x === undefined && series) {
13517
- point.x = x === undefined ? series.autoIncrement() : x;
13586
+ if (x === undefined) {
13587
+ point.x = series.autoIncrement(point);
13588
+ } else {
13589
+ point.x = x;
13590
+ }
13591
+ }
13592
+
13593
+ // Write the last point's name to the names array
13594
+ if (series.xAxis && series.xAxis.names) {
13595
+ series.xAxis.names[point.x] = point.name;
13518
13596
  }
13519
13597
 
13520
13598
  return point;
@@ -13881,18 +13959,38 @@
13881
13959
  * Return an auto incremented x value based on the pointStart and pointInterval options.
13882
13960
  * This is only used if an x value is not given for the point that calls autoIncrement.
13883
13961
  */
13884
- autoIncrement: function () {
13962
+ autoIncrement: function (point) {
13885
13963
 
13886
13964
  var options = this.options,
13887
13965
  xIncrement = this.xIncrement,
13888
13966
  date,
13889
13967
  pointInterval,
13890
- pointIntervalUnit = options.pointIntervalUnit;
13968
+ pointIntervalUnit = options.pointIntervalUnit,
13969
+ xAxis = this.xAxis,
13970
+ explicitCategories,
13971
+ names,
13972
+ nameX;
13891
13973
 
13892
13974
  xIncrement = pick(xIncrement, options.pointStart, 0);
13893
13975
 
13894
13976
  this.pointInterval = pointInterval = pick(this.pointInterval, options.pointInterval, 1);
13895
13977
 
13978
+ // When a point name is given and no x, search for the name in the existing categories,
13979
+ // or if categories aren't provided, search names or create a new category (#2522).
13980
+ if (xAxis && xAxis.categories && point.name) {
13981
+ this.requireSorting = false;
13982
+ explicitCategories = isArray(xAxis.categories);
13983
+ names = explicitCategories ? xAxis.categories : xAxis.names;
13984
+ nameX = inArray(point.name, names); // #2522
13985
+ if (nameX === -1) { // The name is not found in currenct categories
13986
+ if (!explicitCategories) {
13987
+ xIncrement = names.length;
13988
+ }
13989
+ } else {
13990
+ xIncrement = nameX;
13991
+ }
13992
+ }
13993
+
13896
13994
  // Added code for pointInterval strings
13897
13995
  if (pointIntervalUnit) {
13898
13996
  date = new Date(xIncrement);
@@ -14031,7 +14129,6 @@
14031
14129
  chart = series.chart,
14032
14130
  firstPoint = null,
14033
14131
  xAxis = series.xAxis,
14034
- hasCategories = xAxis && !!xAxis.categories,
14035
14132
  i,
14036
14133
  turboThreshold = options.turboThreshold,
14037
14134
  pt,
@@ -14113,9 +14210,6 @@
14113
14210
  pt = { series: series };
14114
14211
  series.pointClass.prototype.applyOptions.apply(pt, [data[i]]);
14115
14212
  series.updateParallelArrays(pt, i);
14116
- if (hasCategories && defined(pt.name)) { // #4401
14117
- xAxis.names[pt.x] = pt.name; // #2046
14118
- }
14119
14213
  }
14120
14214
  }
14121
14215
  }
@@ -14451,7 +14545,7 @@
14451
14545
  yBottom = stackValues[0];
14452
14546
  yValue = stackValues[1];
14453
14547
 
14454
- if (yBottom === stackThreshold) {
14548
+ if (yBottom === stackThreshold && stackIndicator.key === stack[xValue].base) {
14455
14549
  yBottom = pick(threshold, yAxis.min);
14456
14550
  }
14457
14551
  if (yAxis.isLog && yBottom <= 0) { // #1200, #1232
@@ -14486,7 +14580,7 @@
14486
14580
 
14487
14581
 
14488
14582
  // Set client related positions for mouse tracking
14489
- point.clientX = dynamicallyPlaced ? xAxis.translate(xValue, 0, 0, 0, 1) : plotX; // #1514
14583
+ point.clientX = dynamicallyPlaced ? correctFloat(xAxis.translate(xValue, 0, 0, 0, 1)) : plotX; // #1514
14490
14584
 
14491
14585
  point.negative = point.y < (threshold || 0);
14492
14586
 
@@ -14549,10 +14643,15 @@
14549
14643
  );
14550
14644
  }
14551
14645
  chart[sharedClipKey] = clipRect = renderer.clipRect(clipBox);
14646
+ // Create hashmap for series indexes
14647
+ clipRect.count = { length: 0 };
14552
14648
 
14553
14649
  }
14554
14650
  if (animation) {
14555
- clipRect.count += 1;
14651
+ if (!clipRect.count[this.index]) {
14652
+ clipRect.count[this.index] = true;
14653
+ clipRect.count.length += 1;
14654
+ }
14556
14655
  }
14557
14656
 
14558
14657
  if (options.clip !== false) {
@@ -14563,8 +14662,12 @@
14563
14662
 
14564
14663
  // Remove the shared clipping rectangle when all series are shown
14565
14664
  if (!animation) {
14566
- clipRect.count -= 1;
14567
- if (clipRect.count <= 0 && sharedClipKey && chart[sharedClipKey]) {
14665
+ if (clipRect.count[this.index]) {
14666
+ delete clipRect.count[this.index];
14667
+ clipRect.count.length -= 1;
14668
+ }
14669
+
14670
+ if (clipRect.count.length === 0 && sharedClipKey && chart[sharedClipKey]) {
14568
14671
  if (!seriesClipBox) {
14569
14672
  chart[sharedClipKey] = chart[sharedClipKey].destroy();
14570
14673
  }
@@ -14775,7 +14878,7 @@
14775
14878
  if (seriesOptions.marker) { // line, spline, area, areaspline, scatter
14776
14879
 
14777
14880
  // if no hover radius is given, default to normal radius + 2
14778
- stateOptionsHover.radius = stateOptionsHover.radius || normalOptions.radius + stateOptionsHover.radiusPlus;
14881
+ stateOptionsHover.radius = +stateOptionsHover.radius || +normalOptions.radius + +stateOptionsHover.radiusPlus;
14779
14882
  stateOptionsHover.lineWidth = stateOptionsHover.lineWidth || normalOptions.lineWidth + stateOptionsHover.lineWidthPlus;
14780
14883
 
14781
14884
  } else { // column, bar, pie
@@ -14983,6 +15086,7 @@
14983
15086
  step = options.step,
14984
15087
  reversed,
14985
15088
  graphPath = [],
15089
+ xMap = [],
14986
15090
  gap;
14987
15091
 
14988
15092
  points = points || series.points;
@@ -15008,7 +15112,7 @@
15008
15112
 
15009
15113
  var plotX = point.plotX,
15010
15114
  plotY = point.plotY,
15011
- lastPoint = points[i - 1],
15115
+ lastPoint = points[i - 1],
15012
15116
  pathToPoint; // the path to this point from the previous
15013
15117
 
15014
15118
  if ((point.leftCliff || (lastPoint && lastPoint.rightCliff)) && !connectCliffs) {
@@ -15069,12 +15173,18 @@
15069
15173
  ];
15070
15174
  }
15071
15175
 
15176
+ // Prepare for animation. When step is enabled, there are two path nodes for each x value.
15177
+ xMap.push(point.x);
15178
+ if (step) {
15179
+ xMap.push(point.x);
15180
+ }
15072
15181
 
15073
15182
  graphPath.push.apply(graphPath, pathToPoint);
15074
15183
  gap = false;
15075
15184
  }
15076
15185
  });
15077
15186
 
15187
+ graphPath.xMap = xMap;
15078
15188
  series.graphPath = graphPath;
15079
15189
 
15080
15190
  return graphPath;
@@ -15091,7 +15201,6 @@
15091
15201
  lineWidth = options.lineWidth,
15092
15202
  roundCap = options.linecap !== 'square',
15093
15203
  graphPath = (this.gappedPath || this.getGraphPath).call(this),
15094
- fillColor = (this.fillGraph && this.color) || NONE, // polygon series use filled graph
15095
15204
  zones = this.zones;
15096
15205
 
15097
15206
  each(zones, function (threshold, i) {
@@ -15105,13 +15214,14 @@
15105
15214
  attribs;
15106
15215
 
15107
15216
  if (graph) {
15217
+ graph.endX = graphPath.xMap;
15108
15218
  graph.animate({ d: graphPath });
15109
15219
 
15110
- } else if ((lineWidth || fillColor) && graphPath.length) { // #1487
15220
+ } else if (lineWidth && graphPath.length) { // #1487
15111
15221
  attribs = {
15112
15222
  stroke: prop[1],
15113
15223
  'stroke-width': lineWidth,
15114
- fill: fillColor,
15224
+ fill: 'none',
15115
15225
  zIndex: 1 // #1069
15116
15226
  };
15117
15227
  if (prop[2]) {
@@ -15120,11 +15230,18 @@
15120
15230
  attribs['stroke-linecap'] = attribs['stroke-linejoin'] = 'round';
15121
15231
  }
15122
15232
 
15123
- series[graphKey] = series.chart.renderer.path(graphPath)
15233
+ graph = series[graphKey] = series.chart.renderer.path(graphPath)
15124
15234
  .attr(attribs)
15125
15235
  .add(series.group)
15126
15236
  .shadow((i < 2) && options.shadow); // add shadow to normal series (0) or to first zone (1) #3932
15127
15237
  }
15238
+
15239
+ // Helpers for animation
15240
+ if (graph) {
15241
+ graph.startX = graphPath.xMap;
15242
+ //graph.shiftUnit = options.step ? 2 : 1;
15243
+ graph.isArea = graphPath.isArea; // For arearange animation
15244
+ }
15128
15245
  });
15129
15246
  },
15130
15247
 
@@ -15897,6 +16014,11 @@
15897
16014
  stack = stacks[key][x];
15898
16015
  if (y !== null) {
15899
16016
  stack.points[pointKey] = stack.points[series.index] = [pick(stack.cum, stackThreshold)];
16017
+
16018
+ // Record the base of the stack
16019
+ if (!defined(stack.cum)) {
16020
+ stack.base = pointKey;
16021
+ }
15900
16022
  stack.touched = yAxis.stacksTouched;
15901
16023
 
15902
16024
 
@@ -16159,7 +16281,7 @@
16159
16281
  if (point.y === null && graphic) { // #4146
16160
16282
  point.graphic = graphic.destroy();
16161
16283
  }
16162
- if (isObject(options) && !isArray(options)) {
16284
+ if (isObject(options, true)) {
16163
16285
  // Defer the actual redraw until getAttribs has been called (#3260)
16164
16286
  point.redraw = function () {
16165
16287
  if (graphic && graphic.element) {
@@ -16183,7 +16305,7 @@
16183
16305
 
16184
16306
  // Record the options to options.data. If there is an object from before,
16185
16307
  // use point options, otherwise use raw options. (#4701)
16186
- seriesOptions.data[i] = (isObject(seriesOptions.data[i]) && !isArray(seriesOptions.data[i])) ? point.options : options;
16308
+ seriesOptions.data[i] = isObject(seriesOptions.data[i], true) ? point.options : options;
16187
16309
 
16188
16310
  // redraw
16189
16311
  series.isDirty = series.isDirtyData = true;
@@ -16233,12 +16355,8 @@
16233
16355
  var series = this,
16234
16356
  seriesOptions = series.options,
16235
16357
  data = series.data,
16236
- graph = series.graph,
16237
- area = series.area,
16238
16358
  chart = series.chart,
16239
16359
  names = series.xAxis && series.xAxis.names,
16240
- currentShift = (graph && graph.shift) || 0,
16241
- shiftShapes = ['graph', 'area'],
16242
16360
  dataOptions = seriesOptions.data,
16243
16361
  point,
16244
16362
  isInTheMiddle,
@@ -16248,22 +16366,6 @@
16248
16366
 
16249
16367
  setAnimation(animation, chart);
16250
16368
 
16251
- // Make graph animate sideways
16252
- if (shift) {
16253
- i = series.zones.length;
16254
- while (i--) {
16255
- shiftShapes.push('zoneGraph' + i, 'zoneArea' + i);
16256
- }
16257
- each(shiftShapes, function (shape) {
16258
- if (series[shape]) {
16259
- series[shape].shift = currentShift + (seriesOptions.step ? 2 : 1);
16260
- }
16261
- });
16262
- }
16263
- if (area) {
16264
- area.isArea = true; // needed in animation, both with and without shift
16265
- }
16266
-
16267
16369
  // Optional redraw, defaults to true
16268
16370
  redraw = pick(redraw, true);
16269
16371
 
@@ -16455,7 +16557,6 @@
16455
16557
  newOptions = chart.options[this.coll][this.options.index] = merge(this.userOptions, newOptions);
16456
16558
 
16457
16559
  this.destroy(true);
16458
- this._addedPlotLB = this.chart._labelPanes = UNDEFINED; // #1611, #2887, #4314
16459
16560
 
16460
16561
  this.init(chart, extend(newOptions, { events: UNDEFINED }));
16461
16562
 
@@ -16761,6 +16862,7 @@
16761
16862
  areaPath = topPath.concat(bottomPath);
16762
16863
  graphPath = getGraphPath.call(this, graphPoints, false, connectNulls); // TODO: don't set leftCliff and rightCliff when connectNulls?
16763
16864
 
16865
+ areaPath.xMap = topPath.xMap;
16764
16866
  this.areaPath = areaPath;
16765
16867
  return graphPath;
16766
16868
  },
@@ -16795,6 +16897,7 @@
16795
16897
 
16796
16898
  // Create or update the area
16797
16899
  if (area) { // update
16900
+ area.endX = areaPath.xMap;
16798
16901
  area.animate({ d: areaPath });
16799
16902
 
16800
16903
  } else { // create
@@ -16805,10 +16908,13 @@
16805
16908
  if (!prop[2]) {
16806
16909
  attr['fill-opacity'] = pick(options.fillOpacity, 0.75);
16807
16910
  }
16808
- series[areaKey] = series.chart.renderer.path(areaPath)
16911
+ area = series[areaKey] = series.chart.renderer.path(areaPath)
16809
16912
  .attr(attr)
16810
16913
  .add(series.group);
16914
+ area.isArea = true;
16811
16915
  }
16916
+ area.startX = areaPath.xMap;
16917
+ area.shiftUnit = options.step ? 2 : 1;
16812
16918
  });
16813
16919
  },
16814
16920
 
@@ -17611,6 +17717,10 @@
17611
17717
  // Get the total sum
17612
17718
  for (i = 0; i < len; i++) {
17613
17719
  point = points[i];
17720
+ // Disallow negative values (#1530, #3623, #5322)
17721
+ if (point.y < 0) {
17722
+ point.y = null;
17723
+ }
17614
17724
  total += (ignoreHiddenPoint && !point.visible) ? 0 : point.y;
17615
17725
  }
17616
17726
  this.total = total;
@@ -17887,8 +17997,8 @@
17887
17997
  dataLabelsGroup.attr({ opacity: +hasRendered }); // #3300
17888
17998
  if (!hasRendered) {
17889
17999
  addEvent(series, 'afterAnimate', function () {
17890
- if (series.visible) { // #3023, #3024
17891
- dataLabelsGroup.show();
18000
+ if (series.visible) { // #2597, #3023, #3024
18001
+ dataLabelsGroup.show(true);
17892
18002
  }
17893
18003
  dataLabelsGroup[seriesOptions.animation ? 'animate' : 'attr']({ opacity: 1 }, { duration: 200 });
17894
18004
  });