highcharts-rails 4.0.1 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,7 @@
2
2
  // @compilation_level SIMPLE_OPTIMIZATIONS
3
3
 
4
4
  /**
5
- * @license Highcharts JS v4.0.1 (2014-04-24)
5
+ * @license Highcharts JS v4.0.3 (2014-07-03)
6
6
  *
7
7
  * (c) 2009-2014 Torstein Honsi
8
8
  *
@@ -108,7 +108,7 @@ extend(Pane.prototype, {
108
108
  [1, '#DDD']
109
109
  ]
110
110
  },
111
- from: Number.MIN_VALUE, // corrected to axis min
111
+ from: -Number.MAX_VALUE, // corrected to axis min
112
112
  innerRadius: 0,
113
113
  to: Number.MAX_VALUE, // corrected to axis max
114
114
  outerRadius: '105%'
@@ -658,6 +658,7 @@ defaultPlotOptions.arearange = merge(defaultPlotOptions.area, {
658
658
  },
659
659
  trackByArea: true,
660
660
  dataLabels: {
661
+ align: null,
661
662
  verticalAlign: null,
662
663
  xLow: 0,
663
664
  xHigh: 0,
@@ -795,6 +796,7 @@ seriesTypes.arearange = extendClass(seriesTypes.area, {
795
796
  originalDataLabels = [],
796
797
  seriesProto = Series.prototype,
797
798
  dataLabelOptions = this.options.dataLabels,
799
+ align = dataLabelOptions.align,
798
800
  point,
799
801
  inverted = this.chart.inverted;
800
802
 
@@ -818,7 +820,9 @@ seriesTypes.arearange = extendClass(seriesTypes.area, {
818
820
  // Set the default offset
819
821
  point.below = false;
820
822
  if (inverted) {
821
- dataLabelOptions.align = 'left';
823
+ if (!align) {
824
+ dataLabelOptions.align = 'left';
825
+ }
822
826
  dataLabelOptions.x = dataLabelOptions.xHigh;
823
827
  } else {
824
828
  dataLabelOptions.y = dataLabelOptions.yHigh;
@@ -845,7 +849,9 @@ seriesTypes.arearange = extendClass(seriesTypes.area, {
845
849
  // Set the default offset
846
850
  point.below = true;
847
851
  if (inverted) {
848
- dataLabelOptions.align = 'right';
852
+ if (!align) {
853
+ dataLabelOptions.align = 'right';
854
+ }
849
855
  dataLabelOptions.x = dataLabelOptions.xLow;
850
856
  } else {
851
857
  dataLabelOptions.y = dataLabelOptions.yLow;
@@ -855,6 +861,8 @@ seriesTypes.arearange = extendClass(seriesTypes.area, {
855
861
  seriesProto.drawDataLabels.apply(this, arguments);
856
862
  }
857
863
  }
864
+
865
+ dataLabelOptions.align = align;
858
866
 
859
867
  },
860
868
 
@@ -862,7 +870,7 @@ seriesTypes.arearange = extendClass(seriesTypes.area, {
862
870
  seriesTypes.column.prototype.alignDataLabel.apply(this, arguments);
863
871
  },
864
872
 
865
- getSymbol: seriesTypes.column.prototype.getSymbol,
873
+ getSymbol: noop,
866
874
 
867
875
  drawPoints: noop
868
876
  });/**
@@ -931,7 +939,7 @@ seriesTypes.areasplinerange = extendClass(seriesTypes.arearange, {
931
939
  shapeArgs.y = y;
932
940
  });
933
941
  },
934
- trackerGroups: ['group', 'dataLabels'],
942
+ trackerGroups: ['group', 'dataLabelsGroup'],
935
943
  drawGraph: noop,
936
944
  pointAttrToOptions: colProto.pointAttrToOptions,
937
945
  drawPoints: colProto.drawPoints,
@@ -1013,7 +1021,7 @@ var GaugeSeries = {
1013
1021
  drawGraph: noop,
1014
1022
  fixedBox: true,
1015
1023
  forceDL: true,
1016
- trackerGroups: ['group', 'dataLabels'],
1024
+ trackerGroups: ['group', 'dataLabelsGroup'],
1017
1025
 
1018
1026
  /**
1019
1027
  * Calculate paths etc
@@ -1504,7 +1512,12 @@ defaultPlotOptions.waterfall = merge(defaultPlotOptions.column, {
1504
1512
  lineWidth: 1,
1505
1513
  lineColor: '#333',
1506
1514
  dashStyle: 'dot',
1507
- borderColor: '#333'
1515
+ borderColor: '#333',
1516
+ states: {
1517
+ hover: {
1518
+ lineWidthPlus: 0 // #3126
1519
+ }
1520
+ }
1508
1521
  });
1509
1522
 
1510
1523
 
@@ -1535,7 +1548,7 @@ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1535
1548
  translate: function () {
1536
1549
  var series = this,
1537
1550
  options = series.options,
1538
- axis = series.yAxis,
1551
+ yAxis = series.yAxis,
1539
1552
  len,
1540
1553
  i,
1541
1554
  points,
@@ -1544,13 +1557,15 @@ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1544
1557
  stack,
1545
1558
  y,
1546
1559
  previousY,
1560
+ previousIntermediate,
1547
1561
  stackPoint,
1548
- threshold = options.threshold;
1562
+ threshold = options.threshold,
1563
+ tooltipY;
1549
1564
 
1550
1565
  // run column series translate
1551
1566
  seriesTypes.column.prototype.translate.apply(this);
1552
1567
 
1553
- previousY = threshold;
1568
+ previousY = previousIntermediate = threshold;
1554
1569
  points = series.points;
1555
1570
 
1556
1571
  for (i = 0, len = points.length; i < len; i++) {
@@ -1569,13 +1584,18 @@ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1569
1584
 
1570
1585
  // up points
1571
1586
  y = mathMax(previousY, previousY + point.y) + stackPoint[0];
1572
- shapeArgs.y = axis.translate(y, 0, 1);
1587
+ shapeArgs.y = yAxis.translate(y, 0, 1);
1573
1588
 
1574
1589
 
1575
1590
  // sum points
1576
- if (point.isSum || point.isIntermediateSum) {
1577
- shapeArgs.y = axis.translate(stackPoint[1], 0, 1);
1578
- shapeArgs.height = axis.translate(stackPoint[0], 0, 1) - shapeArgs.y;
1591
+ if (point.isSum) {
1592
+ shapeArgs.y = yAxis.translate(stackPoint[1], 0, 1);
1593
+ shapeArgs.height = yAxis.translate(stackPoint[0], 0, 1) - shapeArgs.y;
1594
+
1595
+ } else if (point.isIntermediateSum) {
1596
+ shapeArgs.y = yAxis.translate(stackPoint[1], 0, 1);
1597
+ shapeArgs.height = yAxis.translate(previousIntermediate, 0, 1) - shapeArgs.y;
1598
+ previousIntermediate = stackPoint[1];
1579
1599
 
1580
1600
  // if it's not the sum point, update previous stack end position
1581
1601
  } else {
@@ -1589,8 +1609,17 @@ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1589
1609
  }
1590
1610
 
1591
1611
  point.plotY = shapeArgs.y = mathRound(shapeArgs.y) - (series.borderWidth % 2) / 2;
1592
- shapeArgs.height = mathRound(shapeArgs.height);
1612
+ shapeArgs.height = mathMax(mathRound(shapeArgs.height), 0.001); // #3151
1593
1613
  point.yBottom = shapeArgs.y + shapeArgs.height;
1614
+
1615
+ // Correct tooltip placement (#3014)
1616
+ tooltipY = point.plotY + (point.negative ? shapeArgs.height : 0);
1617
+ if (series.chart.inverted) {
1618
+ point.tooltipPos[0] = yAxis.len - tooltipY;
1619
+ } else {
1620
+ point.tooltipPos[1] = tooltipY;
1621
+ }
1622
+
1594
1623
  }
1595
1624
  },
1596
1625
 
@@ -1622,7 +1651,6 @@ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1622
1651
  yData[i] = sum;
1623
1652
  } else if (y === "intermediateSum" || point.isIntermediateSum) {
1624
1653
  yData[i] = subSum;
1625
- subSum = threshold;
1626
1654
  } else {
1627
1655
  sum += y;
1628
1656
  subSum += y;
@@ -1749,7 +1777,9 @@ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1749
1777
  // 1 - set default options
1750
1778
  defaultPlotOptions.bubble = merge(defaultPlotOptions.scatter, {
1751
1779
  dataLabels: {
1752
- format: '{point.z}',
1780
+ formatter: function () { // #2945
1781
+ return this.point.z;
1782
+ },
1753
1783
  inside: true,
1754
1784
  style: {
1755
1785
  color: 'white',
@@ -2011,14 +2041,14 @@ Axis.prototype.beforePadding = function () {
2011
2041
  // Find the min and max Z
2012
2042
  zData = series.zData;
2013
2043
  if (zData.length) { // #1735
2014
- zMin = math.min(
2044
+ zMin = pick(seriesOptions.zMin, math.min(
2015
2045
  zMin,
2016
2046
  math.max(
2017
2047
  arrayMin(zData),
2018
2048
  seriesOptions.displayNegative === false ? seriesOptions.zThreshold : -Number.MAX_VALUE
2019
2049
  )
2020
- );
2021
- zMax = math.max(zMax, arrayMax(zData));
2050
+ ));
2051
+ zMax = pick(seriesOptions.zMax, math.max(zMax, arrayMax(zData)));
2022
2052
  }
2023
2053
  }
2024
2054
  }
@@ -2908,7 +2908,7 @@ if (CanvasRenderingContext2D) {
2908
2908
  });
2909
2909
  }
2910
2910
  }/**
2911
- * @license Highcharts JS v4.0.1 (2014-04-24)
2911
+ * @license Highcharts JS v4.0.3 (2014-07-03)
2912
2912
  * CanVGRenderer Extension module
2913
2913
  *
2914
2914
  * (c) 2011-2012 Torstein Honsi, Erik Olsson
@@ -24,8 +24,9 @@
24
24
  * - complete : Function(chartOptions)
25
25
  * The callback that is evaluated when the data is finished loading, optionally from an
26
26
  * external source, and parsed. The first argument passed is a finished chart options
27
- * object, containing series and an xAxis with categories if applicable. Thise options
28
- * can be extended with additional options and passed directly to the chart constructor.
27
+ * object, containing the series. Thise options
28
+ * can be extended with additional options and passed directly to the chart constructor. This is
29
+ * related to the parsed callback, that goes in at an earlier stage.
29
30
  *
30
31
  * - csv : String
31
32
  * A comma delimited string to be parsed. Related options are startRow, endRow, startColumn
@@ -57,7 +58,9 @@
57
58
  *
58
59
  * - parsed : Function
59
60
  * A callback function to access the parsed columns, the two-dimentional input data
60
- * array directly, before they are interpreted into series data and categories.
61
+ * array directly, before they are interpreted into series data and categories. See also
62
+ * the complete callback, that goes in on a later stage where the raw columns are interpreted
63
+ * into a Highcharts option structure.
61
64
  *
62
65
  * - parseDate : Function
63
66
  * A callback function to parse string representations of dates into JavaScript timestamps.
@@ -84,7 +87,7 @@
84
87
  // JSLint options:
85
88
  /*global jQuery */
86
89
 
87
- (function (Highcharts) {
90
+ (function (Highcharts) { // docs
88
91
 
89
92
  // Utilities
90
93
  var each = Highcharts.each;
@@ -339,7 +342,7 @@
339
342
  headerRow = null;
340
343
  }
341
344
  });
342
- this.headerRow = 0;
345
+ this.headerRow = 0;
343
346
  },
344
347
 
345
348
  /**
@@ -485,10 +488,11 @@
485
488
  data,
486
489
  i,
487
490
  j,
488
- seriesIndex;
491
+ seriesIndex,
492
+ chartOptions;
489
493
 
490
494
 
491
- if (options.complete) {
495
+ if (options.complete || options.afterComplete) {
492
496
 
493
497
  this.getColumnDistribution();
494
498
 
@@ -557,12 +561,20 @@
557
561
  }
558
562
 
559
563
  // Do the callback
560
- options.complete({
564
+ chartOptions = {
561
565
  xAxis: {
562
566
  type: type
563
567
  },
564
568
  series: series
565
- });
569
+ };
570
+ if (options.complete) {
571
+ options.complete(chartOptions);
572
+ }
573
+ // The afterComplete hook is used internally to avoid conflict with the externally
574
+ // available complete option.
575
+ if (options.afterComplete) {
576
+ options.afterComplete(chartOptions);
577
+ }
566
578
  }
567
579
  }
568
580
  });
@@ -580,14 +592,17 @@
580
592
 
581
593
  if (userOptions && userOptions.data) {
582
594
  Highcharts.data(Highcharts.extend(userOptions.data, {
583
- complete: function (dataOptions) {
595
+ afterComplete: function (dataOptions) {
596
+ var i, series;
584
597
 
585
598
  // Merge series configs
586
599
  if (userOptions.hasOwnProperty('series')) {
587
600
  if (typeof userOptions.series === 'object') {
588
- each(userOptions.series, function (series, i) {
601
+ i = Math.max(userOptions.series.length, dataOptions.series.length);
602
+ while (i--) {
603
+ series = userOptions.series[i] || {};
589
604
  userOptions.series[i] = Highcharts.merge(series, dataOptions.series[i]);
590
- });
605
+ }
591
606
  } else { // Allow merging in dataOptions.series (#2856)
592
607
  delete userOptions.series;
593
608
  }
@@ -17,6 +17,7 @@
17
17
  each = H.each,
18
18
  extend = H.extend,
19
19
  format = H.format,
20
+ pick = H.pick,
20
21
  wrap = H.wrap,
21
22
  Chart = H.Chart,
22
23
  seriesTypes = H.seriesTypes,
@@ -77,7 +78,7 @@
77
78
  visibility: 'inherit'
78
79
  })
79
80
  .animate({
80
- opacity: 1
81
+ opacity: pick(this.newOpacity, 1) // newOpacity used in maps
81
82
  }, animation || {
82
83
  duration: 250
83
84
  });
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v4.0.1 (2014-04-24)
2
+ * @license Highcharts JS v4.0.3 (2014-07-03)
3
3
  * Exporting module
4
4
  *
5
5
  * (c) 2010-2014 Torstein Honsi
@@ -250,6 +250,7 @@ extend(Chart.prototype, {
250
250
  each(chart.series, function (serie) {
251
251
  seriesOptions = merge(serie.options, {
252
252
  animation: false, // turn off animation
253
+ enableMouseTracking: false,
253
254
  showCheckbox: false,
254
255
  visible: serie.visible
255
256
  });
@@ -294,7 +295,10 @@ extend(Chart.prototype, {
294
295
  .replace(/<svg /, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
295
296
  .replace(/ href=/g, ' xlink:href=')
296
297
  .replace(/\n/, ' ')
297
- .replace(/<\/svg>.*?$/, '</svg>') // any HTML added to the container after the SVG (#894)
298
+ // Any HTML added to the container after the SVG (#894)
299
+ .replace(/<\/svg>.*?$/, '</svg>')
300
+ // Batik doesn't support rgba fills and strokes (#3095)
301
+ .replace(/(fill|stroke)="rgba\(([ 0-9]+,[ 0-9]+,[ 0-9]+),([ 0-9\.]+)\)"/g, '$1="rgb($2)" $1-opacity="$3"')
298
302
  /* This fails in IE < 8
299
303
  .replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight
300
304
  return s2 +'.'+ s3[0];
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v4.0.1 (2014-04-24)
2
+ * @license Highcharts JS v4.0.3 (2014-07-03)
3
3
  *
4
4
  * (c) 2011-2014 Torstein Honsi
5
5
  *
@@ -17,6 +17,7 @@ var UNDEFINED,
17
17
  Legend = Highcharts.Legend,
18
18
  LegendSymbolMixin = Highcharts.LegendSymbolMixin,
19
19
  Series = Highcharts.Series,
20
+ SVGRenderer = Highcharts.SVGRenderer,
20
21
 
21
22
  defaultOptions = Highcharts.getOptions(),
22
23
  each = Highcharts.each,
@@ -48,7 +49,7 @@ extend(ColorAxis.prototype, {
48
49
  startOnTick: true,
49
50
  endOnTick: true,
50
51
  offset: 0,
51
- marker: { // docs: use another name?
52
+ marker: {
52
53
  animation: {
53
54
  duration: 50
54
55
  },
@@ -117,6 +118,7 @@ extend(ColorAxis.prototype, {
117
118
  colorCounter = 0,
118
119
  options = this.options;
119
120
  this.dataClasses = dataClasses = [];
121
+ this.legendItems = [];
120
122
 
121
123
  each(userOptions.dataClasses, function (dataClass, i) {
122
124
  var colors;
@@ -213,7 +215,7 @@ extend(ColorAxis.prototype, {
213
215
  if (this.isLog) {
214
216
  value = this.val2lin(value);
215
217
  }
216
- pos = 1 - ((this.max - value) / (this.max - this.min));
218
+ pos = 1 - ((this.max - value) / ((this.max - this.min) || 1));
217
219
  i = stops.length;
218
220
  while (i--) {
219
221
  if (pos > stops[i][0]) {
@@ -225,7 +227,7 @@ extend(ColorAxis.prototype, {
225
227
 
226
228
  // The position within the gradient
227
229
  pos = 1 - (to[0] - pos) / ((to[0] - from[0]) || 1);
228
-
230
+
229
231
  color = this.tweenColors(
230
232
  from.color,
231
233
  to.color,
@@ -236,7 +238,9 @@ extend(ColorAxis.prototype, {
236
238
  },
237
239
 
238
240
  getOffset: function () {
239
- var group = this.legendGroup;
241
+ var group = this.legendGroup,
242
+ sideOffset = this.chart.axisOffset[this.side];
243
+
240
244
  if (group) {
241
245
 
242
246
  Axis.prototype.getOffset.call(this);
@@ -250,6 +254,8 @@ extend(ColorAxis.prototype, {
250
254
 
251
255
  this.added = true;
252
256
  }
257
+ // Reset it to avoid color axis reserving space
258
+ this.chart.axisOffset[this.side] = sideOffset;
253
259
  }
254
260
  },
255
261
 
@@ -281,7 +287,8 @@ extend(ColorAxis.prototype, {
281
287
  box,
282
288
  width = pick(legendOptions.symbolWidth, horiz ? 200 : 12),
283
289
  height = pick(legendOptions.symbolHeight, horiz ? 12 : 200),
284
- labelPadding = pick(legendOptions.labelPadding, horiz ? 10 : 30);
290
+ labelPadding = pick(legendOptions.labelPadding, horiz ? 16 : 30),
291
+ itemDistance = pick(legendOptions.itemDistance, 10);
285
292
 
286
293
  this.setLegendColor();
287
294
 
@@ -297,7 +304,7 @@ extend(ColorAxis.prototype, {
297
304
  box = item.legendSymbol.getBBox();
298
305
 
299
306
  // Set how much space this legend item takes up
300
- this.legendItemWidth = width + padding + (horiz ? 0 : labelPadding);
307
+ this.legendItemWidth = width + padding + (horiz ? itemDistance : labelPadding);
301
308
  this.legendItemHeight = height + padding + (horiz ? labelPadding : 0);
302
309
  },
303
310
  /**
@@ -372,56 +379,58 @@ extend(ColorAxis.prototype, {
372
379
  getDataClassLegendSymbols: function () {
373
380
  var axis = this,
374
381
  chart = this.chart,
375
- legendItems = [],
382
+ legendItems = this.legendItems,
376
383
  legendOptions = chart.options.legend,
377
384
  valueDecimals = legendOptions.valueDecimals,
378
385
  valueSuffix = legendOptions.valueSuffix || '',
379
386
  name;
380
387
 
381
- each(this.dataClasses, function (dataClass, i) {
382
- var vis = true,
383
- from = dataClass.from,
384
- to = dataClass.to;
385
-
386
- // Assemble the default name. This can be overridden by legend.options.labelFormatter
387
- name = '';
388
- if (from === UNDEFINED) {
389
- name = '< ';
390
- } else if (to === UNDEFINED) {
391
- name = '> ';
392
- }
393
- if (from !== UNDEFINED) {
394
- name += numberFormat(from, valueDecimals) + valueSuffix;
395
- }
396
- if (from !== UNDEFINED && to !== UNDEFINED) {
397
- name += ' - ';
398
- }
399
- if (to !== UNDEFINED) {
400
- name += numberFormat(to, valueDecimals) + valueSuffix;
401
- }
402
-
403
- // Add a mock object to the legend items
404
- legendItems.push(extend({
405
- chart: chart,
406
- name: name,
407
- options: {},
408
- drawLegendSymbol: LegendSymbolMixin.drawRectangle,
409
- visible: true,
410
- setState: noop,
411
- setVisible: function () {
412
- vis = this.visible = !vis;
413
- each(axis.series, function (series) {
414
- each(series.points, function (point) {
415
- if (point.dataClass === i) {
416
- point.setVisible(vis);
417
- }
418
- });
419
- });
420
-
421
- chart.legend.colorizeItem(this, vis);
388
+ if (!legendItems.length) {
389
+ each(this.dataClasses, function (dataClass, i) {
390
+ var vis = true,
391
+ from = dataClass.from,
392
+ to = dataClass.to;
393
+
394
+ // Assemble the default name. This can be overridden by legend.options.labelFormatter
395
+ name = '';
396
+ if (from === UNDEFINED) {
397
+ name = '< ';
398
+ } else if (to === UNDEFINED) {
399
+ name = '> ';
422
400
  }
423
- }, dataClass));
424
- });
401
+ if (from !== UNDEFINED) {
402
+ name += numberFormat(from, valueDecimals) + valueSuffix;
403
+ }
404
+ if (from !== UNDEFINED && to !== UNDEFINED) {
405
+ name += ' - ';
406
+ }
407
+ if (to !== UNDEFINED) {
408
+ name += numberFormat(to, valueDecimals) + valueSuffix;
409
+ }
410
+
411
+ // Add a mock object to the legend items
412
+ legendItems.push(extend({
413
+ chart: chart,
414
+ name: name,
415
+ options: {},
416
+ drawLegendSymbol: LegendSymbolMixin.drawRectangle,
417
+ visible: true,
418
+ setState: noop,
419
+ setVisible: function () {
420
+ vis = this.visible = !vis;
421
+ each(axis.series, function (series) {
422
+ each(series.points, function (point) {
423
+ if (point.dataClass === i) {
424
+ point.setVisible(vis);
425
+ }
426
+ });
427
+ });
428
+
429
+ chart.legend.colorizeItem(this, vis);
430
+ }
431
+ }, dataClass));
432
+ });
433
+ }
425
434
  return legendItems;
426
435
  },
427
436
  name: '' // Prevents 'undefined' in legend in IE8
@@ -489,6 +498,7 @@ var colorSeriesMixin = {
489
498
  trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
490
499
  getSymbol: noop,
491
500
  parallelArrays: ['x', 'y', 'value'],
501
+ colorKey: 'value',
492
502
 
493
503
  /**
494
504
  * In choropleth maps, the color is a result of the value, so this needs translation too
@@ -496,13 +506,14 @@ var colorSeriesMixin = {
496
506
  translateColors: function () {
497
507
  var series = this,
498
508
  nullColor = this.options.nullColor,
499
- colorAxis = this.colorAxis;
509
+ colorAxis = this.colorAxis,
510
+ colorKey = this.colorKey;
500
511
 
501
512
  each(this.data, function (point) {
502
- var value = point.value,
513
+ var value = point[colorKey],
503
514
  color;
504
515
 
505
- color = value === null ? nullColor : colorAxis ? colorAxis.toColor(value, point) : (point.color) || series.color;
516
+ color = value === null ? nullColor : (colorAxis && value !== undefined) ? colorAxis.toColor(value, point) : point.color || series.color;
506
517
 
507
518
  if (color) {
508
519
  point.color = color;
@@ -510,6 +521,55 @@ var colorSeriesMixin = {
510
521
  });
511
522
  }
512
523
  };
524
+
525
+
526
+ /**
527
+ * Wrap the buildText method and add the hook for add text stroke
528
+ */
529
+ wrap(SVGRenderer.prototype, 'buildText', function (proceed, wrapper) {
530
+
531
+ var textStroke = wrapper.styles && wrapper.styles.HcTextStroke;
532
+
533
+ proceed.call(this, wrapper);
534
+
535
+ // Apply the text stroke
536
+ if (textStroke && wrapper.applyTextStroke) {
537
+ wrapper.applyTextStroke(textStroke);
538
+ }
539
+ });
540
+
541
+ /**
542
+ * Apply an outside text stroke to data labels, based on the custom CSS property, HcTextStroke.
543
+ * Consider moving this to Highcharts core, also makes sense on stacked columns etc.
544
+ */
545
+ SVGRenderer.prototype.Element.prototype.applyTextStroke = function (textStroke) {
546
+ var elem = this.element,
547
+ tspans,
548
+ firstChild;
549
+
550
+ textStroke = textStroke.split(' ');
551
+ tspans = elem.getElementsByTagName('tspan');
552
+ firstChild = elem.firstChild;
553
+
554
+ // In order to get the right y position of the clones,
555
+ // copy over the y setter
556
+ this.ySetter = this.xSetter;
557
+
558
+ each([].slice.call(tspans), function (tspan, y) {
559
+ var clone;
560
+ if (y === 0) {
561
+ tspan.setAttribute('x', elem.getAttribute('x'));
562
+ if ((y = elem.getAttribute('y')) !== null) {
563
+ tspan.setAttribute('y', y);
564
+ }
565
+ }
566
+ clone = tspan.cloneNode(1);
567
+ clone.setAttribute('stroke', textStroke[1]);
568
+ clone.setAttribute('stroke-width', textStroke[0]);
569
+ clone.setAttribute('stroke-linejoin', 'round');
570
+ elem.insertBefore(clone, firstChild);
571
+ });
572
+ };
513
573
  /**
514
574
  * Extend the default options with map options
515
575
  */
@@ -518,14 +578,16 @@ defaultOptions.plotOptions.heatmap = merge(defaultOptions.plotOptions.scatter, {
518
578
  borderWidth: 0,
519
579
  nullColor: '#F8F8F8',
520
580
  dataLabels: {
521
- format: '{point.value}',
581
+ formatter: function () { // #2945
582
+ return this.point.value;
583
+ },
522
584
  verticalAlign: 'middle',
523
585
  crop: false,
524
586
  overflow: false,
525
587
  style: {
526
588
  color: 'white',
527
589
  fontWeight: 'bold',
528
- textShadow: '0 0 5px black'
590
+ HcTextStroke: '1px rgba(0,0,0,0.5)'
529
591
  }
530
592
  },
531
593
  marker: null,
@@ -584,6 +646,13 @@ seriesTypes.heatmap = extendClass(seriesTypes.scatter, merge(colorSeriesMixin, {
584
646
  });
585
647
 
586
648
  series.translateColors();
649
+
650
+ // Make sure colors are updated on colorAxis update (#2893)
651
+ if (this.chart.hasRendered) {
652
+ each(series.points, function (point) {
653
+ point.shapeArgs.fill = point.color;
654
+ });
655
+ }
587
656
  },
588
657
  drawPoints: seriesTypes.column.prototype.drawPoints,
589
658
  animate: noop,