highcharts-rails 4.2.5 → 4.2.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 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
  });