highcharts-rails 4.0.3 → 4.0.4

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: 246fa26d563f5ebbff59b1fad5fd84c66c8139ed
4
- data.tar.gz: c866482da07406051a1cf89456b8ffb981b8a2b7
3
+ metadata.gz: d185bef7f4a8caf4ea1681609d988ffe9c347458
4
+ data.tar.gz: 7e6465866c350bc31edccdb052bcb424516121e3
5
5
  SHA512:
6
- metadata.gz: 1b22d1db2a1152606cb5fab1e3c3a7b073e6ee8f45bf1d84d686f4b7f251bc9d34373bff24336a14fd55be63ee55cdd4f32befa0c1f676bd4df8a3e3cbbd6b9f
7
- data.tar.gz: 9a7c6ac887b3282e97490c4050b95505fd2c927a57937c3966b9c8648bd4a6b1448c8acd3a43503e615906deb4295c867936516889eb248acc1ec41e8daa3b2c
6
+ metadata.gz: c785f77428acad531cb8c7f6b4eade835f2f6c80f41ce0e036e8d7d7d684f869f97bd4e83df14595f3fd2513d3f1470691fe3cd694bd1ba35255d5310ec95675
7
+ data.tar.gz: ec31b0e80b55506cd16b54975c7c5e940808b90809ced51bb54922c564b440604c95ee923054d1f884354652f89e72dc280c812ba6b44d11088a2294268b48c1
data/CHANGELOG.markdown CHANGED
@@ -1,3 +1,39 @@
1
+ # 4.0.4 / 2014-09-02
2
+
3
+ * Updated Highcharts to 4.0.4
4
+ * Added more date parsing logic to the data module. Now integrates with Date.js, and uses Date.parse. Tries to parse all dates, but falls back to categories if dates are not sorted (which may be a sign that parsing went wrong).
5
+ * Added support for setting marker image dimensions. Closes #1807. Closes #1817.
6
+ * Added a better default value for xAxis.allowDecimals. Don't allow decimals in X value ranges that look like years. Closes #3363.
7
+ * Added warning on trying to plot negative points on a logarithmic axis.
8
+ * Allow changing "Date" class used to support other calendars. Added new option global.Date.
9
+ * Allow overriding Highcharts.numberFormat from the outside. Closes #3284.
10
+ * Made point.click event work in combination with drilldown charts.
11
+ * Fixed #3381 3D pies, wrong z index applied to sides
12
+ * Fixed #3279, column z issues in 3d
13
+ * Fixed #3397, footerFormat does not replace variables
14
+ * Speed optimization of Series.setData, related to #3260.
15
+ * Fixed #2909, a regression causing chart click event not to fire when zoom enabled on touch devices.
16
+ * Fixed #3334, missing animations in 3d pies
17
+ * Fixed issue causing markers to show even on dense line series, in spite of new logic in 4.x where it should depend on series density.
18
+ * Fixed #3202, tick marks being drawn in unwanted positions when tickInterval was set on categorized axis.
19
+ * Fixed #424, wrong tooltip position for column series in a pane position
20
+ * Fixed #3352, JavaScript errors on clicking category labels on async drilldown.
21
+ * Fixed #3344, drilldown axis label style inconsistent after redraw.
22
+ * Fixed #3353, wrong axis minimum and maximum on thresholded series when switching from linear to logarithmic axes type.
23
+ * Fixed #3342, memory leaks in jQuery 2.x when repeatedly reinstanciating charts or destroying and recreating renderer primitives.
24
+ * Fixed memory leak on addPoint caused by adding empty names to the Axis.names lookup table.
25
+ * Fixed #3328, 3D Columns and null values
26
+ * Fixes #3317, extra tick added when there are only two ticks (start and end)
27
+ * Fixed #3315 by disallowing duplicate ids in drilldown.
28
+ * Fixed #3182, three level drilldown broken when drilling up and down again on the same series.
29
+ * Fixed #3276 with HTML markup in element titles when a label is shortened by ellipsis.
30
+ * Fixed #3088, tooltip blocking new mouse interaction after hiding when useHTML is true.
31
+ * Fixed #3285, funnel and pyramid center option not working for vertical dimension.
32
+ * Fixed #3300 where data labels would remain semi-transparent when chart updated in the middle of labels fading in.
33
+ * Fixed #3295, labels do not render 0 as value
34
+ * Fixed #3282, plotBorder width changed sign, causing a strange animation
35
+ * Fixed #3245, waterfall series failed when first element was Sum or IntermediateSum
36
+
1
37
  # 4.0.3 / 2014-07-03
2
38
 
3
39
  * Updated Highcharts to 4.0.3
@@ -2,7 +2,7 @@
2
2
  // @compilation_level SIMPLE_OPTIMIZATIONS
3
3
 
4
4
  /**
5
- * @license Highcharts JS v4.0.3 (2014-07-03)
5
+ * @license Highcharts JS v4.0.4 (2014-09-02)
6
6
  *
7
7
  * (c) 2009-2014 Torstein Honsi
8
8
  *
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  // JSLint options:
13
- /*global Highcharts, document, window, navigator, setInterval, clearInterval, clearTimeout, setTimeout, location, jQuery, $, console, each, grep */
13
+ /*global Highcharts, HighchartsAdapter, document, window, navigator, setInterval, clearInterval, clearTimeout, setTimeout, location, jQuery, $, console, each, grep */
14
14
  /*jslint ass: true, sloppy: true, forin: true, plusplus: true, nomen: true, vars: true, regexp: true, newcap: true, browser: true, continue: true, white: true */
15
15
  (function () {
16
16
  // encapsulated variables
@@ -57,7 +57,7 @@ var UNDEFINED,
57
57
  charts = [],
58
58
  chartCount = 0,
59
59
  PRODUCT = 'Highcharts',
60
- VERSION = '4.0.3',
60
+ VERSION = '4.0.4',
61
61
 
62
62
  // some constants for frequently used strings
63
63
  DIV = 'div',
@@ -82,6 +82,7 @@ var UNDEFINED,
82
82
  STROKE_WIDTH = 'stroke-width',
83
83
 
84
84
  // time methods, changed based on whether or not UTC is used
85
+ Date, // Allow using a different Date class
85
86
  makeTime,
86
87
  timezoneOffset,
87
88
  getMinutes,
@@ -363,7 +364,8 @@ function extendClass(parent, members) {
363
364
  * @param {String} thousandsSep The thousands separator, defaults to the one given in the lang options
364
365
  */
365
366
  function numberFormat(number, decimals, decPoint, thousandsSep) {
366
- var lang = defaultOptions.lang,
367
+ var externalFn = Highcharts.numberFormat,
368
+ lang = defaultOptions.lang,
367
369
  // http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_number_format/
368
370
  n = +number || 0,
369
371
  c = decimals === -1 ?
@@ -375,8 +377,10 @@ function numberFormat(number, decimals, decPoint, thousandsSep) {
375
377
  i = String(pInt(n = mathAbs(n).toFixed(c))),
376
378
  j = i.length > 3 ? i.length % 3 : 0;
377
379
 
378
- return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) +
379
- (c ? d + mathAbs(n - i).toFixed(c).slice(2) : "");
380
+ return externalFn !== numberFormat ?
381
+ externalFn(number, decimals, decPoint, thousandsSep) :
382
+ (s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) +
383
+ (c ? d + mathAbs(n - i).toFixed(c).slice(2) : ""));
380
384
  }
381
385
 
382
386
  /**
@@ -563,7 +567,7 @@ function getMagnitude(num) {
563
567
  * @param {Number} magnitude
564
568
  * @param {Object} options
565
569
  */
566
- function normalizeTickInterval(interval, multiples, magnitude, options) {
570
+ function normalizeTickInterval(interval, multiples, magnitude, allowDecimals) {
567
571
  var normalized, i;
568
572
 
569
573
  // round to a tenfold of 1, 2, 2.5 or 5
@@ -575,7 +579,7 @@ function normalizeTickInterval(interval, multiples, magnitude, options) {
575
579
  multiples = [1, 2, 2.5, 5, 10];
576
580
 
577
581
  // the allowDecimals option
578
- if (options && options.allowDecimals === false) {
582
+ if (allowDecimals === false) {
579
583
  if (magnitude === 1) {
580
584
  multiples = [1, 2, 5, 10];
581
585
  } else if (magnitude <= 0.1) {
@@ -852,12 +856,7 @@ pathAnim = {
852
856
  init: function (pathAnim) {
853
857
 
854
858
  // extend the animate function to allow SVG animations
855
- var Fx = $.fx,
856
- Step = Fx.step,
857
- dSetter,
858
- Tween = $.Tween,
859
- propHooks = Tween && Tween.propHooks,
860
- opacityHook = $.cssHooks.opacity;
859
+ var Fx = $.fx;
861
860
 
862
861
  /*jslint unparam: true*//* allow unused param x in this function */
863
862
  $.extend($.easing, {
@@ -869,15 +868,15 @@ pathAnim = {
869
868
 
870
869
  // extend some methods to check for elem.attr, which means it is a Highcharts SVG object
871
870
  $.each(['cur', '_default', 'width', 'height', 'opacity'], function (i, fn) {
872
- var obj = Step,
871
+ var obj = Fx.step,
873
872
  base;
874
873
 
875
874
  // Handle different parent objects
876
875
  if (fn === 'cur') {
877
876
  obj = Fx.prototype; // 'cur', the getter, relates to Fx.prototype
878
877
 
879
- } else if (fn === '_default' && Tween) { // jQuery 1.8 model
880
- obj = propHooks[fn];
878
+ } else if (fn === '_default' && $.Tween) { // jQuery 1.8 model
879
+ obj = $.Tween.propHooks[fn];
881
880
  fn = 'set';
882
881
  }
883
882
 
@@ -911,13 +910,12 @@ pathAnim = {
911
910
  });
912
911
 
913
912
  // Extend the opacity getter, needed for fading opacity with IE9 and jQuery 1.10+
914
- wrap(opacityHook, 'get', function (proceed, elem, computed) {
913
+ wrap($.cssHooks.opacity, 'get', function (proceed, elem, computed) {
915
914
  return elem.attr ? (elem.opacity || 0) : proceed.call(this, elem, computed);
916
915
  });
917
916
 
918
-
919
917
  // Define the setter function for d (path definitions)
920
- dSetter = function (fx) {
918
+ this.addAnimSetter('d', function (fx) {
921
919
  var elem = fx.elem,
922
920
  ends;
923
921
 
@@ -931,21 +929,9 @@ pathAnim = {
931
929
  fx.started = true;
932
930
  }
933
931
 
934
-
935
- // interpolate each value of the path
932
+ // Interpolate each value of the path
936
933
  elem.attr('d', pathAnim.step(fx.start, fx.end, fx.pos, elem.toD));
937
- };
938
-
939
- // jQuery 1.8 style
940
- if (Tween) {
941
- propHooks.d = {
942
- set: dSetter
943
- };
944
- // pre 1.8
945
- } else {
946
- // animate paths
947
- Step.d = dSetter;
948
- }
934
+ });
949
935
 
950
936
  /**
951
937
  * Utility for iterating over an array. Parameters are reversed compared to jQuery.
@@ -1006,6 +992,20 @@ pathAnim = {
1006
992
 
1007
993
  },
1008
994
 
995
+ /**
996
+ * Add an animation setter for a specific property
997
+ */
998
+ addAnimSetter: function (prop, setter) {
999
+ // jQuery 1.8 style
1000
+ if ($.Tween) {
1001
+ $.Tween.propHooks[prop] = {
1002
+ set: setter
1003
+ };
1004
+ // pre 1.8
1005
+ } else {
1006
+ $.fx.step[prop] = setter;
1007
+ }
1008
+ },
1009
1009
 
1010
1010
  /**
1011
1011
  * Downloads a script and executes a callback when done.
@@ -1185,6 +1185,7 @@ pathAnim = {
1185
1185
  if (params.opacity !== UNDEFINED && el.attr) {
1186
1186
  params.opacity += 'px'; // force jQuery to use same logic as width and height (#2161)
1187
1187
  }
1188
+ el.hasAnim = 1; // #3342
1188
1189
  $el.animate(params, options);
1189
1190
 
1190
1191
  },
@@ -1192,7 +1193,9 @@ pathAnim = {
1192
1193
  * Stop running animation
1193
1194
  */
1194
1195
  stop: function (el) {
1195
- $(el).stop();
1196
+ if (el.hasAnim) { // #3342, memory leak on calling $(el) from destroy
1197
+ $(el).stop();
1198
+ }
1196
1199
  }
1197
1200
  });
1198
1201
  }(win.jQuery));
@@ -1267,8 +1270,8 @@ defaultOptions = {
1267
1270
  global: {
1268
1271
  useUTC: true,
1269
1272
  //timezoneOffset: 0,
1270
- canvasToolsURL: 'http://code.highcharts.com/4.0.3/modules/canvas-tools.js',
1271
- VMLRadialGradientURL: 'http://code.highcharts.com/4.0.3/gfx/vml-radial-gradient.png'
1273
+ canvasToolsURL: 'http://code.highcharts.com/4.0.4/modules/canvas-tools.js',
1274
+ VMLRadialGradientURL: 'http://code.highcharts.com/4.0.4/gfx/vml-radial-gradient.png'
1272
1275
  },
1273
1276
  chart: {
1274
1277
  //animation: true,
@@ -1592,6 +1595,7 @@ function setTimeMethods() {
1592
1595
  SET = useUTC ? 'setUTC' : 'set';
1593
1596
 
1594
1597
 
1598
+ Date = defaultOptions.global.Date || window.Date;
1595
1599
  timezoneOffset = ((useUTC && defaultOptions.global.timezoneOffset) || 0) * 60000;
1596
1600
  makeTime = useUTC ? Date.UTC : function (year, month, date, hours, minutes, seconds) {
1597
1601
  return new Date(
@@ -2436,10 +2440,10 @@ SVGElement.prototype = {
2436
2440
  // IE9-11 doesn't handle visibilty:inherit well, so we remove the attribute instead (#2881)
2437
2441
  if (inherit && this.element.namespaceURI === SVG_NS) {
2438
2442
  this.element.removeAttribute('visibility');
2439
- return this;
2440
2443
  } else {
2441
- return this.attr({ visibility: inherit ? 'inherit' : VISIBLE });
2444
+ this.attr({ visibility: inherit ? 'inherit' : VISIBLE });
2442
2445
  }
2446
+ return this;
2443
2447
  },
2444
2448
 
2445
2449
  /**
@@ -2456,7 +2460,7 @@ SVGElement.prototype = {
2456
2460
  }, {
2457
2461
  duration: duration || 150,
2458
2462
  complete: function () {
2459
- elemWrapper.hide();
2463
+ elemWrapper.attr({ y: -9999 }); // #3088, assuming we're only using this for tooltips
2460
2464
  }
2461
2465
  });
2462
2466
  },
@@ -2701,14 +2705,14 @@ SVGElement.prototype = {
2701
2705
  .replace(/dot/g, '1,3,')
2702
2706
  .replace('dash', '4,3,')
2703
2707
  .replace(/,$/, '')
2704
- .replace('solid', 1)
2705
2708
  .split(','); // ending comma
2706
2709
 
2707
2710
  i = value.length;
2708
2711
  while (i--) {
2709
2712
  value[i] = pInt(value[i]) * this['stroke-width'];
2710
2713
  }
2711
- value = value.join(',');
2714
+ value = value.join(',')
2715
+ .replace('NaN', 'none'); // #3226
2712
2716
  this.element.setAttribute('stroke-dasharray', value);
2713
2717
  }
2714
2718
  },
@@ -2725,7 +2729,7 @@ SVGElement.prototype = {
2725
2729
  titleNode = doc.createElementNS(SVG_NS, 'title');
2726
2730
  this.element.appendChild(titleNode);
2727
2731
  }
2728
- titleNode.textContent = value;
2732
+ titleNode.textContent = pick(value, '').replace(/<[^>]*>/g, ''); // #3276
2729
2733
  },
2730
2734
  textSetter: function (value) {
2731
2735
  if (value !== this.textStr) {
@@ -3520,7 +3524,7 @@ SVGRenderer.prototype = {
3520
3524
  };
3521
3525
 
3522
3526
  imageSrc = symbol.match(imageRegex)[1];
3523
- imageSize = symbolSizes[imageSrc];
3527
+ imageSize = symbolSizes[imageSrc] || (options && options.width && options.height && [options.width, options.height]);
3524
3528
 
3525
3529
  // Ireate the image synchronously, add attribs async
3526
3530
  obj = this.image(imageSrc)
@@ -3534,7 +3538,6 @@ SVGRenderer.prototype = {
3534
3538
  centerImage(obj, imageSize);
3535
3539
  } else {
3536
3540
  // Initialize image to be 0 size so export will still function if there's no cached sizes.
3537
- //
3538
3541
  obj.attr({ width: 0, height: 0 });
3539
3542
 
3540
3543
  // Create a dummy JavaScript image to get the width and height. Due to a bug in IE < 8,
@@ -3938,7 +3941,7 @@ SVGRenderer.prototype = {
3938
3941
  wrapper.onAdd = function () {
3939
3942
  text.add(wrapper);
3940
3943
  wrapper.attr({
3941
- text: str || '', // alignment is available now
3944
+ text: (str || str === 0) ? str : '', // alignment is available now // #3295: 0 not rendered if given as a value
3942
3945
  x: x,
3943
3946
  y: y
3944
3947
  });
@@ -5595,8 +5598,7 @@ Tick.prototype = {
5595
5598
 
5596
5599
  // prepare CSS
5597
5600
  css = width && { width: mathMax(1, mathRound(width - 2 * (labelOptions.padding || 10))) + PX };
5598
- css = extend(css, labelOptions.style);
5599
-
5601
+
5600
5602
  // first call
5601
5603
  if (!defined(label)) {
5602
5604
  attr = {
@@ -5619,7 +5621,7 @@ Tick.prototype = {
5619
5621
  )
5620
5622
  .attr(attr)
5621
5623
  // without position absolute, IE export sometimes is wrong
5622
- .css(css)
5624
+ .css(extend(css, labelOptions.style))
5623
5625
  .add(axis.labelGroup) :
5624
5626
  null;
5625
5627
 
@@ -5692,14 +5694,15 @@ Tick.prototype = {
5692
5694
  axisRight,
5693
5695
  neighbour,
5694
5696
  neighbourEdge,
5695
- line = this.label.line || 0,
5697
+ line = this.label.line,
5698
+ lineIndex = line || 0,
5696
5699
  labelEdge = axis.labelEdge,
5697
5700
  justifyLabel = axis.justifyLabels && (isFirst || isLast),
5698
5701
  justifyToPlot;
5699
5702
 
5700
5703
  // Hide it if it now overlaps the neighbour label
5701
- if (labelEdge[line] === UNDEFINED || pxPos + leftSide > labelEdge[line]) {
5702
- labelEdge[line] = pxPos + rightSide;
5704
+ if (labelEdge[lineIndex] === UNDEFINED || pxPos + leftSide > labelEdge[lineIndex]) {
5705
+ labelEdge[lineIndex] = pxPos + rightSide;
5703
5706
 
5704
5707
  } else if (!justifyLabel) {
5705
5708
  show = false;
@@ -6473,7 +6476,8 @@ Axis.prototype = {
6473
6476
  //axis.tickInterval = UNDEFINED;
6474
6477
  //axis.minorTickInterval = UNDEFINED;
6475
6478
 
6476
- axis.tickmarkOffset = (axis.categories && options.tickmarkPlacement === 'between') ? 0.5 : 0;
6479
+ axis.tickmarkOffset = (axis.categories && options.tickmarkPlacement === 'between' &&
6480
+ pick(options.tickInterval, 1) === 1) ? 0.5 : 0; // #3202
6477
6481
 
6478
6482
  // Major ticks
6479
6483
  axis.ticks = {};
@@ -6641,8 +6645,8 @@ Axis.prototype = {
6641
6645
 
6642
6646
  axis.hasVisibleSeries = false;
6643
6647
 
6644
- // reset dataMin and dataMax in case we're redrawing
6645
- axis.dataMin = axis.dataMax = null;
6648
+ // Reset properties in case we're redrawing (#3353)
6649
+ axis.dataMin = axis.dataMax = axis.ignoreMinPadding = axis.ignoreMaxPadding = null;
6646
6650
 
6647
6651
  if (axis.buildStacks) {
6648
6652
  axis.buildStacks();
@@ -7204,7 +7208,14 @@ Axis.prototype = {
7204
7208
  // for linear axes, get magnitude and normalize the interval
7205
7209
  if (!isDatetimeAxis && !isLog) { // linear
7206
7210
  if (!tickIntervalOption) {
7207
- axis.tickInterval = normalizeTickInterval(axis.tickInterval, null, getMagnitude(axis.tickInterval), options);
7211
+ axis.tickInterval = normalizeTickInterval(
7212
+ axis.tickInterval,
7213
+ null,
7214
+ getMagnitude(axis.tickInterval),
7215
+ // If the tick interval is between 1 and 5 and the axis max is in the order of
7216
+ // thousands, chances are we are dealing with years. Don't allow decimals. #3363.
7217
+ pick(options.allowDecimals, !(axis.tickInterval > 1 && axis.tickInterval < 5 && axis.max > 1000 && axis.max < 9999))
7218
+ );
7208
7219
  }
7209
7220
  }
7210
7221
 
@@ -7254,11 +7265,6 @@ Axis.prototype = {
7254
7265
  minPointOffset = axis.minPointOffset || 0,
7255
7266
  singlePad;
7256
7267
 
7257
- // Prevent all ticks from being removed (#3195)
7258
- if (!startOnTick && !endOnTick && !categories && tickPositions.length === 2) {
7259
- tickPositions.splice(1, 0, (roundedMax + roundedMin) / 2);
7260
- }
7261
-
7262
7268
  if (startOnTick) {
7263
7269
  axis.min = roundedMin;
7264
7270
  } else if (axis.min - minPointOffset > roundedMin) {
@@ -7271,6 +7277,11 @@ Axis.prototype = {
7271
7277
  tickPositions.pop();
7272
7278
  }
7273
7279
 
7280
+ // If no tick are left, set one tick in the middle (#3195)
7281
+ if (tickPositions.length === 0 && defined(roundedMin)) {
7282
+ tickPositions.push((roundedMax + roundedMin) / 2);
7283
+ }
7284
+
7274
7285
  // When there is only one point, or all points have the same value on this axis, then min
7275
7286
  // and max are equal and tickPositions.length is 0 or 1. In this case, add some padding
7276
7287
  // in order to center the point, but leave it with one tick. #1337.
@@ -8238,9 +8249,9 @@ Axis.prototype.getTimeTicks = function (normalizedInterval, min, max, startOfWee
8238
8249
  var time = minDate.getTime(),
8239
8250
  minMonth = minDate[getMonth](),
8240
8251
  minDateDate = minDate[getDate](),
8241
- localTimezoneOffset = useUTC ?
8242
- timezoneOffset :
8243
- (24 * 3600 * 1000 + minDate.getTimezoneOffset() * 60 * 1000) % (24 * 3600 * 1000); // #950
8252
+ localTimezoneOffset = (timeUnits.day +
8253
+ (useUTC ? timezoneOffset : minDate.getTimezoneOffset() * 60 * 1000)
8254
+ ) % timeUnits.day; // #950, #3359
8244
8255
 
8245
8256
  // iterate and add tick positions at appropriate values
8246
8257
  while (time < max) {
@@ -8582,7 +8593,7 @@ Tooltip.prototype = {
8582
8593
  /**
8583
8594
  * Hide the tooltip
8584
8595
  */
8585
- hide: function () {
8596
+ hide: function (delay) {
8586
8597
  var tooltip = this,
8587
8598
  hoverPoints;
8588
8599
 
@@ -8593,7 +8604,7 @@ Tooltip.prototype = {
8593
8604
  this.hideTimer = setTimeout(function () {
8594
8605
  tooltip.label.fadeOut();
8595
8606
  tooltip.isHidden = true;
8596
- }, pick(this.options.hideDelay, 500));
8607
+ }, pick(delay, this.options.hideDelay, 500));
8597
8608
 
8598
8609
  // hide previous hoverPoints and set new
8599
8610
  if (hoverPoints) {
@@ -9165,7 +9176,7 @@ Pointer.prototype = {
9165
9176
  *
9166
9177
  * @param allowMove {Boolean} Instead of destroying the tooltip altogether, allow moving it if possible
9167
9178
  */
9168
- reset: function (allowMove) {
9179
+ reset: function (allowMove, delay) {
9169
9180
  var pointer = this,
9170
9181
  chart = pointer.chart,
9171
9182
  hoverSeries = chart.hoverSeries,
@@ -9200,7 +9211,7 @@ Pointer.prototype = {
9200
9211
  }
9201
9212
 
9202
9213
  if (tooltip) {
9203
- tooltip.hide();
9214
+ tooltip.hide(delay);
9204
9215
  }
9205
9216
 
9206
9217
  if (pointer._onDocumentMouseMove) {
@@ -9716,7 +9727,7 @@ extend(Highcharts.Pointer.prototype, {
9716
9727
  selectionMarker = self.selectionMarker,
9717
9728
  transform = {},
9718
9729
  fireClickEvent = touchesLength === 1 && ((self.inClass(e.target, PREFIX + 'tracker') &&
9719
- chart.runTrackerClick) || chart.runChartClick),
9730
+ chart.runTrackerClick) || self.runChartClick),
9720
9731
  clip = {};
9721
9732
 
9722
9733
  // On touch devices, only proceed to trigger click if a handler is defined
@@ -9752,6 +9763,7 @@ extend(Highcharts.Pointer.prototype, {
9752
9763
  bounds.max = mathMax(axis.pos + axis.len, absMax + minPixelPadding);
9753
9764
  }
9754
9765
  });
9766
+ self.res = true; // reset on next move
9755
9767
 
9756
9768
  // Event type is touchmove, handle panning and pinching
9757
9769
  } else if (pinchDown.length) { // can be 0 when releasing, if touchend fires first
@@ -9774,6 +9786,9 @@ extend(Highcharts.Pointer.prototype, {
9774
9786
  // Optionally move the tooltip on touchmove
9775
9787
  if (!hasZoom && followTouchMove && touchesLength === 1) {
9776
9788
  this.runPointActions(self.normalize(e));
9789
+ } else if (self.res) {
9790
+ self.res = false;
9791
+ this.reset(false, 0);
9777
9792
  }
9778
9793
  }
9779
9794
  },
@@ -11739,7 +11754,7 @@ Chart.prototype = {
11739
11754
  .add();
11740
11755
  } else {
11741
11756
  plotBorder.animate(
11742
- plotBorder.crisp({ x: plotLeft, y: plotTop, width: plotWidth, height: plotHeight })
11757
+ plotBorder.crisp({ x: plotLeft, y: plotTop, width: plotWidth, height: plotHeight, strokeWidth: -plotBorderWidth }) //#3282 plotBorder should be negative
11743
11758
  );
11744
11759
  }
11745
11760
  }
@@ -12744,7 +12759,7 @@ Series.prototype = {
12744
12759
  // cheaper, allows animation, and keeps references to points.
12745
12760
  if (updatePoints !== false && dataLength && oldDataLength === dataLength && !series.cropped && !series.hasGroupedData) {
12746
12761
  each(data, function (point, i) {
12747
- oldData[i].update(point, false);
12762
+ oldData[i].update(point, false, null, false);
12748
12763
  });
12749
12764
 
12750
12765
  } else {
@@ -12879,14 +12894,15 @@ Series.prototype = {
12879
12894
  return false;
12880
12895
  }
12881
12896
 
12882
-
12883
- // optionally filter out points outside the plot area
12884
- if (isCartesian && series.sorted && (!cropThreshold || dataLength > cropThreshold || series.forceCrop)) {
12885
-
12897
+ if (xAxis) {
12886
12898
  xExtremes = xAxis.getExtremes(); // corrected for log axis (#3053)
12887
12899
  min = xExtremes.min;
12888
12900
  max = xExtremes.max;
12901
+ }
12889
12902
 
12903
+ // optionally filter out points outside the plot area
12904
+ if (isCartesian && series.sorted && (!cropThreshold || dataLength > cropThreshold || series.forceCrop)) {
12905
+
12890
12906
  // it's outside current extremes
12891
12907
  if (processedXData[dataLength - 1] < min || processedXData[0] > max) {
12892
12908
  processedXData = [];
@@ -12911,6 +12927,7 @@ Series.prototype = {
12911
12927
  if (!cropped && processedXData[i] > min && processedXData[i] < max) {
12912
12928
  activePointCount++;
12913
12929
  }
12930
+
12914
12931
  if (distance > 0 && (closestPointRange === UNDEFINED || distance < closestPointRange)) {
12915
12932
  closestPointRange = distance;
12916
12933
 
@@ -13011,6 +13028,7 @@ Series.prototype = {
13011
13028
  // splat the y data in case of ohlc data array
13012
13029
  points[i] = (new pointClass()).init(series, [processedXData[i]].concat(splat(processedYData[i])));
13013
13030
  }
13031
+ points[i].index = cursor; // For faster access in Point.update
13014
13032
  }
13015
13033
 
13016
13034
  // Hide cropped-away points - this only runs when the number of points is above cropThreshold, or when
@@ -13121,6 +13139,7 @@ Series.prototype = {
13121
13139
  // Discard disallowed y values for log axes
13122
13140
  if (yAxis.isLog && yValue <= 0) {
13123
13141
  point.y = yValue = null;
13142
+ error(10);
13124
13143
  }
13125
13144
 
13126
13145
  // Get the plotX translation
@@ -13295,12 +13314,13 @@ Series.prototype = {
13295
13314
  seriesMarkerOptions = options.marker,
13296
13315
  seriesPointAttr = series.pointAttr[''],
13297
13316
  pointMarkerOptions,
13317
+ hasPointMarker,
13298
13318
  enabled,
13299
13319
  isInside,
13300
13320
  markerGroup = series.markerGroup,
13301
13321
  globallyEnabled = pick(
13302
13322
  seriesMarkerOptions.enabled,
13303
- series.activePointCount < (0.5 * series.xAxis.len / seriesMarkerOptions.radius)
13323
+ !series.requireSorting || series.activePointCount < (0.5 * series.xAxis.len / seriesMarkerOptions.radius)
13304
13324
  );
13305
13325
 
13306
13326
  if (seriesMarkerOptions.enabled !== false || series._hasPointMarkers) {
@@ -13312,6 +13332,7 @@ Series.prototype = {
13312
13332
  plotY = point.plotY;
13313
13333
  graphic = point.graphic;
13314
13334
  pointMarkerOptions = point.marker || {};
13335
+ hasPointMarker = !!point.marker;
13315
13336
  enabled = (globallyEnabled && pointMarkerOptions.enabled === UNDEFINED) || pointMarkerOptions.enabled;
13316
13337
  isInside = chart.isInsidePlot(mathRound(plotX), plotY, chart.inverted); // #1858
13317
13338
 
@@ -13339,7 +13360,8 @@ Series.prototype = {
13339
13360
  plotX - radius,
13340
13361
  plotY - radius,
13341
13362
  2 * radius,
13342
- 2 * radius
13363
+ 2 * radius,
13364
+ hasPointMarker ? pointMarkerOptions : seriesMarkerOptions
13343
13365
  )
13344
13366
  .attr(pointAttr)
13345
13367
  .add(markerGroup);
@@ -13949,6 +13971,12 @@ Series.prototype = {
13949
13971
  series.clipNeg();
13950
13972
  }
13951
13973
 
13974
+ each(series.points, function (point) {
13975
+ if (point.redraw) {
13976
+ point.redraw();
13977
+ }
13978
+ });
13979
+
13952
13980
  // draw the data labels (inn pies they go before the points)
13953
13981
  if (series.drawDataLabels) {
13954
13982
  series.drawDataLabels();
@@ -14476,39 +14504,40 @@ extend(Point.prototype, {
14476
14504
  * configuration
14477
14505
  *
14478
14506
  */
14479
- update: function (options, redraw, animation) {
14507
+ update: function (options, redraw, animation, runEvent) {
14480
14508
  var point = this,
14481
14509
  series = point.series,
14482
14510
  graphic = point.graphic,
14483
14511
  i,
14484
- data = series.data,
14485
14512
  chart = series.chart,
14486
14513
  seriesOptions = series.options;
14487
14514
 
14488
14515
  redraw = pick(redraw, true);
14489
14516
 
14490
- // fire the event with a default handler of doing the update
14491
- point.firePointEvent('update', { options: options }, function () {
14517
+ function update() {
14492
14518
 
14493
14519
  point.applyOptions(options);
14494
14520
 
14495
- // update visuals
14496
- if (isObject(options)) {
14497
- series.getAttribs();
14498
- if (graphic) {
14499
- if (options && options.marker && options.marker.symbol) {
14500
- point.graphic = graphic.destroy();
14501
- } else {
14502
- graphic.attr(point.pointAttr[point.state || '']);
14521
+ // Update visuals
14522
+ if (isObject(options) && !isArray(options)) {
14523
+ // Defer the actual redraw until getAttribs has been called (#3260)
14524
+ point.redraw = function () {
14525
+ if (graphic) {
14526
+ if (options && options.marker && options.marker.symbol) {
14527
+ point.graphic = graphic.destroy();
14528
+ } else {
14529
+ graphic.attr(point.pointAttr[point.state || '']);
14530
+ }
14503
14531
  }
14504
- }
14505
- if (options && options.dataLabels && point.dataLabel) { // #2468
14506
- point.dataLabel = point.dataLabel.destroy();
14507
- }
14532
+ if (options && options.dataLabels && point.dataLabel) { // #2468
14533
+ point.dataLabel = point.dataLabel.destroy();
14534
+ }
14535
+ point.redraw = null;
14536
+ };
14508
14537
  }
14509
14538
 
14510
14539
  // record changes in the parallel arrays
14511
- i = inArray(point, data);
14540
+ i = point.index;
14512
14541
  series.updateParallelArrays(point, i);
14513
14542
 
14514
14543
  seriesOptions.data[i] = point.options;
@@ -14525,7 +14554,14 @@ extend(Point.prototype, {
14525
14554
  if (redraw) {
14526
14555
  chart.redraw(animation);
14527
14556
  }
14528
- });
14557
+ }
14558
+
14559
+ // Fire the event with a default handler of doing the update
14560
+ if (runEvent === false) { // When called from setData
14561
+ update();
14562
+ } else {
14563
+ point.firePointEvent('update', { options: options }, update);
14564
+ }
14529
14565
  },
14530
14566
 
14531
14567
  /**
@@ -14631,7 +14667,7 @@ extend(Series.prototype, {
14631
14667
  series.updateParallelArrays(point, 'splice', i, 0, 0); // insert undefined item
14632
14668
  series.updateParallelArrays(point, i); // update it
14633
14669
 
14634
- if (names) {
14670
+ if (names && point.name) {
14635
14671
  names[x] = point.name;
14636
14672
  }
14637
14673
  dataOptions.splice(i, 0, options);
@@ -15395,8 +15431,10 @@ var ColumnSeries = extendClass(Series, {
15395
15431
  point.barX = barX;
15396
15432
  point.pointWidth = pointWidth;
15397
15433
 
15398
- // Fix the tooltip on center of grouped columns (#1216)
15399
- point.tooltipPos = chart.inverted ? [yAxis.len - plotY, series.xAxis.len - barX - barW / 2] : [barX + barW / 2, plotY];
15434
+ // Fix the tooltip on center of grouped columns (#1216, #424)
15435
+ point.tooltipPos = chart.inverted ?
15436
+ [yAxis.len - plotY, series.xAxis.len - barX - barW / 2] :
15437
+ [barX + barW / 2, plotY + yAxis.pos - chart.plotTop];
15400
15438
 
15401
15439
  // Round off to obtain crisp edges and avoid overlapping with neighbours (#2694)
15402
15440
  right = mathRound(barX + barW) + xCrisp;
@@ -16068,6 +16106,7 @@ Series.prototype.drawDataLabels = function () {
16068
16106
  points = series.points,
16069
16107
  pointOptions,
16070
16108
  generalOptions,
16109
+ hasRendered = series.hasRendered || 0,
16071
16110
  str,
16072
16111
  dataLabelsGroup;
16073
16112
 
@@ -16086,14 +16125,16 @@ Series.prototype.drawDataLabels = function () {
16086
16125
  options.zIndex || 6
16087
16126
  );
16088
16127
 
16089
- if (!series.hasRendered && pick(options.defer, true)) {
16090
- dataLabelsGroup.attr({ opacity: 0 });
16091
- addEvent(series, 'afterAnimate', function () {
16092
- if (series.visible) { // #3023, #3024
16093
- dataLabelsGroup.show();
16094
- }
16095
- dataLabelsGroup[seriesOptions.animation ? 'animate' : 'attr']({ opacity: 1 }, { duration: 200 });
16096
- });
16128
+ if (pick(options.defer, true)) {
16129
+ dataLabelsGroup.attr({ opacity: +hasRendered }); // #3300
16130
+ if (!hasRendered) {
16131
+ addEvent(series, 'afterAnimate', function () {
16132
+ if (series.visible) { // #3023, #3024
16133
+ dataLabelsGroup.show();
16134
+ }
16135
+ dataLabelsGroup[seriesOptions.animation ? 'animate' : 'attr']({ opacity: 1 }, { duration: 200 });
16136
+ });
16137
+ }
16097
16138
  }
16098
16139
 
16099
16140
  // Make the labels for each point