highcharts-rails 5.0.0 → 5.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.markdown +99 -0
  4. data/Gemfile +1 -1
  5. data/README.markdown +2 -1
  6. data/Rakefile +28 -2
  7. data/app/assets/javascripts/highcharts.js +3935 -2584
  8. data/app/assets/javascripts/highcharts/highcharts-3d.js +44 -10
  9. data/app/assets/javascripts/highcharts/highcharts-more.js +32 -12
  10. data/app/assets/javascripts/highcharts/modules/accessibility.js +85 -18
  11. data/app/assets/javascripts/highcharts/modules/annotations.js +1 -1
  12. data/app/assets/javascripts/highcharts/modules/boost.js +34 -19
  13. data/app/assets/javascripts/highcharts/modules/broken-axis.js +1 -1
  14. data/app/assets/javascripts/highcharts/modules/data.js +2 -2
  15. data/app/assets/javascripts/highcharts/modules/drilldown.js +4 -3
  16. data/app/assets/javascripts/highcharts/modules/exporting.js +15 -14
  17. data/app/assets/javascripts/highcharts/modules/funnel.js +1 -1
  18. data/app/assets/javascripts/highcharts/modules/grid-axis.js +547 -0
  19. data/app/assets/javascripts/highcharts/modules/heatmap.js +17 -2
  20. data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +1 -1
  21. data/app/assets/javascripts/highcharts/modules/offline-exporting.js +115 -73
  22. data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +1 -1
  23. data/app/assets/javascripts/highcharts/modules/series-label.js +210 -148
  24. data/app/assets/javascripts/highcharts/modules/solid-gauge.js +30 -10
  25. data/app/assets/javascripts/highcharts/modules/treemap.js +6 -1
  26. data/app/assets/javascripts/highcharts/modules/xrange-series.js +278 -0
  27. data/lib/highcharts/version.rb +1 -1
  28. metadata +3 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.0 (2016-09-29)
2
+ * @license Highcharts JS v5.0.3 (2016-11-18)
3
3
  *
4
4
  * (c) 2009-2016 Torstein Honsi
5
5
  *
@@ -67,6 +67,14 @@
67
67
  tickLength: 5,
68
68
  showInLegend: true
69
69
  },
70
+
71
+ // Properties to preserve after destroy, for Axis.update (#5881)
72
+ keepProps: ['legendGroup', 'legendItem', 'legendSymbol']
73
+ .concat(Axis.prototype.keepProps),
74
+
75
+ /**
76
+ * Initialize the color axis
77
+ */
70
78
  init: function(chart, userOptions) {
71
79
  var horiz = chart.options.legend.layout !== 'vertical',
72
80
  options;
@@ -584,6 +592,13 @@
584
592
  * Mixin for maps and heatmaps
585
593
  */
586
594
  H.colorPointMixin = {
595
+ /**
596
+ * Color points have a value option that determines whether or not it is a null point
597
+ */
598
+ isValid: function() {
599
+ return this.value !== null;
600
+ },
601
+
587
602
  /**
588
603
  * Set the visibility of a single point
589
604
  */
@@ -627,7 +642,7 @@
627
642
  color;
628
643
 
629
644
  color = point.options.color ||
630
- (value === null ? nullColor : (colorAxis && value !== undefined) ? colorAxis.toColor(value, point) : point.color || series.color);
645
+ (point.isNull ? nullColor : (colorAxis && value !== undefined) ? colorAxis.toColor(value, point) : point.color || series.color);
631
646
 
632
647
  if (color) {
633
648
  point.color = color;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.0 (2016-09-29)
2
+ * @license Highcharts JS v5.0.3 (2016-11-18)
3
3
  * Plugin for displaying a message when there is no data visible in chart.
4
4
  *
5
5
  * (c) 2010-2016 Highsoft AS
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.0 (2016-09-29)
2
+ * @license Highcharts JS v5.0.3 (2016-11-18)
3
3
  * Client side exporting module
4
4
  *
5
5
  * (c) 2015 Torstein Honsi / Oystein Moseng
@@ -29,6 +29,7 @@
29
29
  win = Highcharts.win,
30
30
  nav = win.navigator,
31
31
  doc = win.document,
32
+ each = Highcharts.each,
32
33
  domurl = win.URL || win.webkitURL || win,
33
34
  isMSBrowser = /Edge\/|Trident\/|MSIE /.test(nav.userAgent),
34
35
  loadEventDeferDelay = isMSBrowser ? 150 : 0; // Milliseconds to defer image load event handlers to offset IE bug
@@ -49,6 +50,9 @@
49
50
  script.type = 'text/javascript';
50
51
  script.src = scriptLocation;
51
52
  script.onload = callback;
53
+ script.onerror = function() {
54
+ console.error('Error loading script', scriptLocation); // eslint-disable-line no-console
55
+ };
52
56
 
53
57
  head.appendChild(script);
54
58
  }
@@ -161,23 +165,57 @@
161
165
  img.src = imageURL;
162
166
  };
163
167
 
164
- // Get data URL to an image of an SVG and call download on it
165
- Highcharts.downloadSVGLocal = function(svg, filename, imageType, scale, failCallback, successCallback) {
168
+ /**
169
+ * Get data URL to an image of an SVG and call download on it
170
+ *
171
+ * options object:
172
+ * filename: Name of resulting downloaded file without extension
173
+ * type: File type of resulting download
174
+ * scale: Scaling factor of downloaded image compared to source
175
+ * libURL: URL pointing to location of dependency scripts to download on demand
176
+ */
177
+ Highcharts.downloadSVGLocal = function(svg, options, failCallback, successCallback) {
166
178
  var svgurl,
167
179
  blob,
168
180
  objectURLRevoke = true,
169
181
  finallyHandler,
170
- libURL = Highcharts.getOptions().exporting.libURL;
171
-
172
- /*
173
- function svgToPdf(svgElement, margin) {
174
- var width = svgElement.width.baseVal.value + 2 * margin;
175
- var height = svgElement.height.baseVal.value + 2 * margin;
176
- var pdf = new win.jsPDF('l', 'pt', [width, height]); // eslint-disable-line new-cap
177
- win.svgElementToPdf(svgElement, pdf, { removeInvalid: true });
178
- return pdf.output('datauristring');
179
- }
180
- */
182
+ libURL = options.libURL || Highcharts.getOptions().exporting.libURL,
183
+ dummySVGContainer = doc.createElement('div'),
184
+ imageType = options.type || 'image/png',
185
+ filename = (options.filename || 'chart') + '.' + (imageType === 'image/svg+xml' ? 'svg' : imageType.split('/')[1]),
186
+ scale = options.scale || 1;
187
+
188
+ libURL = libURL.slice(-1) !== '/' ? libURL + '/' : libURL; // Allow libURL to end with or without fordward slash
189
+
190
+ function svgToPdf(svgElement, margin) {
191
+ var width = svgElement.width.baseVal.value + 2 * margin,
192
+ height = svgElement.height.baseVal.value + 2 * margin,
193
+ pdf = new win.jsPDF('l', 'pt', [width, height]); // eslint-disable-line new-cap
194
+ win.svgElementToPdf(svgElement, pdf, {
195
+ removeInvalid: true
196
+ });
197
+ return pdf.output('datauristring');
198
+ }
199
+
200
+ function downloadPDF() {
201
+ dummySVGContainer.innerHTML = svg;
202
+ var textElements = dummySVGContainer.getElementsByTagName('text'),
203
+ svgElementStyle = dummySVGContainer.getElementsByTagName('svg')[0].style;
204
+ // Workaround for the text styling. Making sure it does pick up the root element
205
+ each(textElements, function(el) {
206
+ each(['font-family', 'font-size'], function(property) {
207
+ if (!el.style[property] && svgElementStyle[property]) {
208
+ el.style[property] = svgElementStyle[property];
209
+ }
210
+ });
211
+ el.style['font-family'] = el.style['font-family'] && el.style['font-family'].split(' ').splice(-1);
212
+ });
213
+ var svgData = svgToPdf(dummySVGContainer.firstChild, 0);
214
+ Highcharts.downloadURL(svgData, filename);
215
+ if (successCallback) {
216
+ successCallback();
217
+ }
218
+ }
181
219
 
182
220
  // Initiate download depending on file type
183
221
  if (imageType === 'image/svg+xml') {
@@ -197,20 +235,20 @@
197
235
  } catch (e) {
198
236
  failCallback();
199
237
  }
200
- /*} else if (imageType === 'application/pdf') {
201
- doc.getElementsByTagName('svg')[0].id = 'svgElement';
202
- // you should set the format dynamically, write [width, height] instead of 'a4'
203
- if (win.jsPDF && win.svgElementToPdf) {
204
- var dummyContainer = doc.createElement('div');
205
- dummyContainer.innerHTML = svg;
206
- setTimeout(function () {
207
- var data = svgToPdf(dummyContainer.firstChild, 0);
208
- Highcharts.downloadURL(data, filename);
209
- if (successCallback) {
210
- successCallback();
211
- }
212
- }, 100);
213
- }*/
238
+ } else if (imageType === 'application/pdf') {
239
+ if (win.jsPDF && win.svgElementToPdf) {
240
+ downloadPDF();
241
+ } else {
242
+ // Must load pdf libraries first
243
+ objectURLRevoke = true; // Don't destroy the object URL yet since we are doing things asynchronously. A cleaner solution would be nice, but this will do for now.
244
+ getScript(libURL + 'jspdf.js', function() {
245
+ getScript(libURL + 'rgbcolor.js', function() {
246
+ getScript(libURL + 'svg2pdf.js', function() {
247
+ downloadPDF();
248
+ });
249
+ });
250
+ });
251
+ }
214
252
  } else {
215
253
  // PNG/JPEG download - create bitmap from SVG
216
254
 
@@ -262,7 +300,6 @@
262
300
  } else {
263
301
  // Must load canVG first
264
302
  objectURLRevoke = true; // Don't destroy the object URL yet since we are doing things asynchronously. A cleaner solution would be nice, but this will do for now.
265
- libURL = libURL.substr[-1] !== '/' ? libURL + '/' : libURL; // Allow libURL to end with or without fordward slash
266
303
  getScript(libURL + 'rgbcolor.js', function() { // Get RGBColor.js first
267
304
  getScript(libURL + 'canvg.js', function() {
268
305
  downloadWithCanVG();
@@ -307,10 +344,18 @@
307
344
  };
308
345
 
309
346
  // Hook into getSVG to get a copy of the chart copy's container
310
- Highcharts.wrap(Highcharts.Chart.prototype, 'getChartHTML', function(proceed) {
311
- chartCopyContainer = this.container.cloneNode(true);
312
- return proceed.apply(this, Array.prototype.slice.call(arguments, 1));
313
- });
347
+ Highcharts.wrap(
348
+ Highcharts.Chart.prototype,
349
+ 'getChartHTML',
350
+ function(proceed) {
351
+ var ret = proceed.apply(
352
+ this,
353
+ Array.prototype.slice.call(arguments, 1)
354
+ );
355
+ chartCopyContainer = this.container.cloneNode(true);
356
+ return ret;
357
+ }
358
+ );
314
359
 
315
360
  // Trigger hook to get chart copy
316
361
  chart.getSVGForExport(options, chartOptions);
@@ -349,7 +394,6 @@
349
394
  Highcharts.Chart.prototype.exportChartLocal = function(exportingOptions, chartOptions) {
350
395
  var chart = this,
351
396
  options = Highcharts.merge(chart.options.exporting, exportingOptions),
352
- imageType = options && options.type || 'image/png',
353
397
  fallbackToExportServer = function() {
354
398
  if (options.fallbackToExportServer === false) {
355
399
  if (options.error) {
@@ -362,12 +406,12 @@
362
406
  }
363
407
  },
364
408
  svgSuccess = function(svg) {
365
- var filename = (options.filename || 'chart') + '.' + (imageType === 'image/svg+xml' ? 'svg' : imageType.split('/')[1]);
366
- Highcharts.downloadSVGLocal(svg, filename, imageType, options.scale, fallbackToExportServer);
409
+ Highcharts.downloadSVGLocal(svg, options, fallbackToExportServer);
367
410
  };
368
411
 
369
- // If we have embedded images and are exporting to JPEG/PNG, Microsoft browsers won't handle it, so fall back
370
- if (isMSBrowser && imageType !== 'image/svg+xml' && chart.container.getElementsByTagName('image').length) {
412
+ // If we have embedded images and are exporting to JPEG/PNG, Microsoft browsers won't handle it, so fall back.
413
+ // Also fall back for embedded images with PDF.
414
+ if ((isMSBrowser && options.type !== 'image/svg+xml' || options.type === 'application/pdf') && chart.container.getElementsByTagName('image').length) {
371
415
  fallbackToExportServer();
372
416
  return;
373
417
  }
@@ -377,45 +421,43 @@
377
421
 
378
422
  // Extend the default options to use the local exporter logic
379
423
  merge(true, Highcharts.getOptions().exporting, {
380
- libURL: 'http://code.highcharts.com@product.cdnpath@/5.0.0/lib/',
424
+ libURL: 'https://code.highcharts.com/5.0.3/lib/',
381
425
  buttons: {
382
426
  contextButton: {
383
427
  menuItems: [{
384
- textKey: 'printChart',
385
- onclick: function() {
386
- this.print();
387
- }
388
- }, {
389
- separator: true
390
- }, {
391
- textKey: 'downloadPNG',
392
- onclick: function() {
393
- this.exportChartLocal();
394
- }
395
- }, {
396
- textKey: 'downloadJPEG',
397
- onclick: function() {
398
- this.exportChartLocal({
399
- type: 'image/jpeg'
400
- });
401
- }
402
- }, {
403
- textKey: 'downloadSVG',
404
- onclick: function() {
405
- this.exportChartLocal({
406
- type: 'image/svg+xml'
407
- });
408
- }
428
+ textKey: 'printChart',
429
+ onclick: function() {
430
+ this.print();
431
+ }
432
+ }, {
433
+ separator: true
434
+ }, {
435
+ textKey: 'downloadPNG',
436
+ onclick: function() {
437
+ this.exportChartLocal();
438
+ }
439
+ }, {
440
+ textKey: 'downloadJPEG',
441
+ onclick: function() {
442
+ this.exportChartLocal({
443
+ type: 'image/jpeg'
444
+ });
445
+ }
446
+ }, {
447
+ textKey: 'downloadSVG',
448
+ onclick: function() {
449
+ this.exportChartLocal({
450
+ type: 'image/svg+xml'
451
+ });
452
+ }
453
+ }, {
454
+ textKey: 'downloadPDF',
455
+ onclick: function() {
456
+ this.exportChartLocal({
457
+ type: 'application/pdf'
458
+ });
409
459
  }
410
- /*, {
411
- textKey: 'downloadPDF',
412
- onclick: function () {
413
- this.exportChartLocal({
414
- type: 'application/pdf'
415
- });
416
- }
417
- }*/
418
- ]
460
+ }]
419
461
  }
420
462
  }
421
463
  });
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.0 (2016-09-29)
2
+ * @license Highcharts JS v5.0.3 (2016-11-18)
3
3
  *
4
4
  * (c) 2009-2016 Torstein Honsi
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.0 (2016-09-29)
2
+ * @license Highcharts JS v5.0.3 (2016-11-18)
3
3
  *
4
4
  * (c) 2009-2016 Torstein Honsi
5
5
  *
@@ -352,189 +352,251 @@
352
352
 
353
353
  };
354
354
 
355
-
356
355
  /**
357
356
  * The main initiator method that runs on chart level after initiation and redraw. It runs in
358
357
  * a timeout to prevent locking, and loops over all series, taking all series and labels into
359
358
  * account when placing the labels.
360
359
  */
361
- function drawLabels(proceed) {
360
+ Chart.prototype.drawSeriesLabels = function() {
361
+ var chart = this,
362
+ labelSeries = this.labelSeries;
362
363
 
363
- var chart = this;
364
+ chart.boxesToAvoid = [];
364
365
 
365
- proceed.call(chart);
366
+ // Build the interpolated points
367
+ each(labelSeries, function(series) {
368
+ series.interpolatedPoints = series.getPointsOnGraph();
366
369
 
367
- clearTimeout(chart.seriesLabelTimer);
370
+ each(series.options.label.boxesToAvoid || [], function(box) {
371
+ chart.boxesToAvoid.push(box);
372
+ });
373
+ });
374
+
375
+ each(chart.series, function(series) {
376
+ var bBox,
377
+ x,
378
+ y,
379
+ results = [],
380
+ clearPoint,
381
+ i,
382
+ best,
383
+ inverted = chart.inverted,
384
+ paneLeft = inverted ? series.yAxis.pos : series.xAxis.pos,
385
+ paneTop = inverted ? series.xAxis.pos : series.yAxis.pos,
386
+ paneWidth = chart.inverted ? series.yAxis.len : series.xAxis.len,
387
+ paneHeight = chart.inverted ? series.xAxis.len : series.yAxis.len,
388
+ points = series.interpolatedPoints,
389
+ label = series.labelBySeries;
390
+
391
+ function insidePane(x, y, bBox) {
392
+ return x > paneLeft && x <= paneLeft + paneWidth - bBox.width &&
393
+ y >= paneTop && y <= paneTop + paneHeight - bBox.height;
394
+ }
368
395
 
369
- chart.seriesLabelTimer = setTimeout(function() {
396
+ if (series.visible && points) {
397
+ if (!label) {
398
+ series.labelBySeries = label = chart.renderer
399
+ .label(series.name, 0, -9999, 'connector')
400
+ .css(extend({
401
+ color: series.color
402
+ }, series.options.label.styles))
403
+ .attr({
404
+ padding: 0,
405
+ opacity: 0,
406
+ stroke: series.color,
407
+ 'stroke-width': 1
408
+ })
409
+ .add(series.group)
410
+ .animate({
411
+ opacity: 1
412
+ }, {
413
+ duration: 200
414
+ });
415
+ }
370
416
 
371
- chart.boxesToAvoid = [];
417
+ bBox = label.getBBox();
418
+ bBox.width = Math.round(bBox.width);
372
419
 
373
- // Build the interpolated points
374
- each(chart.series, function(series) {
375
- var options = series.options.label;
376
- if (options.enabled && series.visible && (series.graph || series.area)) {
377
- series.interpolatedPoints = series.getPointsOnGraph();
420
+ // Ideal positions are centered above or below a point on right side
421
+ // of chart
422
+ for (i = points.length - 1; i > 0; i -= 1) {
423
+
424
+ // Right - up
425
+ x = points[i].chartX + labelDistance;
426
+ y = points[i].chartY - bBox.height - labelDistance;
427
+ if (insidePane(x, y, bBox)) {
428
+ best = series.checkClearPoint(
429
+ x,
430
+ y,
431
+ bBox
432
+ );
433
+ }
434
+ if (best) {
435
+ results.push(best);
436
+ }
437
+
438
+ // Right - down
439
+ x = points[i].chartX + labelDistance;
440
+ y = points[i].chartY + labelDistance;
441
+ if (insidePane(x, y, bBox)) {
442
+ best = series.checkClearPoint(
443
+ x,
444
+ y,
445
+ bBox
446
+ );
447
+ }
448
+ if (best) {
449
+ results.push(best);
450
+ }
451
+
452
+ // Left - down
453
+ x = points[i].chartX - bBox.width - labelDistance;
454
+ y = points[i].chartY + labelDistance;
455
+ if (insidePane(x, y, bBox)) {
456
+ best = series.checkClearPoint(
457
+ x,
458
+ y,
459
+ bBox
460
+ );
461
+ }
462
+ if (best) {
463
+ results.push(best);
464
+ }
465
+
466
+ // Left - up
467
+ x = points[i].chartX - bBox.width - labelDistance;
468
+ y = points[i].chartY - bBox.height - labelDistance;
469
+ if (insidePane(x, y, bBox)) {
470
+ best = series.checkClearPoint(
471
+ x,
472
+ y,
473
+ bBox
474
+ );
475
+ }
476
+ if (best) {
477
+ results.push(best);
478
+ }
378
479
 
379
- each(options.boxesToAvoid || [], function(box) {
380
- chart.boxesToAvoid.push(box);
381
- });
382
480
  }
383
- });
384
481
 
385
- each(chart.series, function(series) {
386
- var bBox,
387
- x,
388
- y,
389
- results = [],
390
- clearPoint,
391
- i,
392
- best,
393
- inverted = chart.inverted,
394
- paneLeft = inverted ? series.yAxis.pos : series.xAxis.pos,
395
- paneTop = inverted ? series.xAxis.pos : series.yAxis.pos,
396
- paneWidth = chart.inverted ? series.yAxis.len : series.xAxis.len,
397
- paneHeight = chart.inverted ? series.xAxis.len : series.yAxis.len,
398
- points = series.interpolatedPoints;
399
-
400
- function insidePane(x, y, bBox) {
401
- return x > paneLeft && x <= paneLeft + paneWidth - bBox.width &&
402
- y >= paneTop && y <= paneTop + paneHeight - bBox.height;
482
+ // Brute force, try all positions on the chart in a 16x16 grid
483
+ if (!results.length) {
484
+ for (x = paneLeft + paneWidth - bBox.width; x >= paneLeft; x -= 16) {
485
+ for (y = paneTop; y < paneTop + paneHeight - bBox.height; y += 16) {
486
+ clearPoint = series.checkClearPoint(x, y, bBox, true);
487
+ if (clearPoint) {
488
+ results.push(clearPoint);
489
+ }
490
+ }
491
+ }
403
492
  }
404
493
 
405
- if (series.visible && points) {
494
+ if (results.length) {
495
+
496
+ results.sort(function(a, b) {
497
+ return b.weight - a.weight;
498
+ });
499
+
500
+ best = results[0];
501
+
502
+ chart.boxesToAvoid.push({
503
+ left: best.x,
504
+ right: best.x + bBox.width,
505
+ top: best.y,
506
+ bottom: best.y + bBox.height
507
+ });
406
508
 
407
- if (!series.labelBySeries) {
408
- series.labelBySeries = chart.renderer.label(series.name, 0, -9999, 'connector')
409
- .css(extend({
410
- color: series.color
411
- }, series.options.label.styles))
509
+ // Move it if needed
510
+ if (Math.round(best.x) !== Math.round(label.x) ||
511
+ Math.round(best.y) !== Math.round(label.y)) {
512
+ series.labelBySeries
412
513
  .attr({
413
- padding: 0,
414
514
  opacity: 0,
415
- stroke: series.color,
416
- 'stroke-width': 1
515
+ x: best.x - paneLeft,
516
+ y: best.y - paneTop,
517
+ anchorX: best.connectorPoint && best.connectorPoint.plotX,
518
+ anchorY: best.connectorPoint && best.connectorPoint.plotY
417
519
  })
418
- .add(series.group)
419
520
  .animate({
420
521
  opacity: 1
421
- }, {
422
- duration: 200
423
522
  });
424
- }
425
523
 
426
- bBox = series.labelBySeries.getBBox();
427
- bBox.width = Math.round(bBox.width);
428
-
429
- // Ideal positions are centered above or below a point on right side of chart
430
- for (i = points.length - 1; i > 0; i -= 1) {
431
-
432
- // Right - up
433
- x = points[i].chartX + labelDistance;
434
- y = points[i].chartY - bBox.height - labelDistance;
435
- if (insidePane(x, y, bBox)) {
436
- best = series.checkClearPoint(
437
- x,
438
- y,
439
- bBox
440
- );
441
- }
442
- if (best) {
443
- results.push(best);
444
- }
524
+ // Record closest point to stick to for sync redraw
525
+ series.options.kdNow = true;
526
+ series.buildKDTree();
527
+ var closest = series.searchPoint({
528
+ chartX: best.x,
529
+ chartY: best.y
530
+ }, true);
531
+ label.closest = [
532
+ closest,
533
+ best.x - paneLeft - closest.plotX,
534
+ best.y - paneTop - closest.plotY
535
+ ];
445
536
 
446
- // Right - down
447
- x = points[i].chartX + labelDistance;
448
- y = points[i].chartY + labelDistance;
449
- if (insidePane(x, y, bBox)) {
450
- best = series.checkClearPoint(
451
- x,
452
- y,
453
- bBox
454
- );
455
- }
456
- if (best) {
457
- results.push(best);
458
- }
537
+ }
459
538
 
460
- // Left - down
461
- x = points[i].chartX - bBox.width - labelDistance;
462
- y = points[i].chartY + labelDistance;
463
- if (insidePane(x, y, bBox)) {
464
- best = series.checkClearPoint(
465
- x,
466
- y,
467
- bBox
468
- );
469
- }
470
- if (best) {
471
- results.push(best);
472
- }
539
+ } else if (label) {
540
+ series.labelBySeries = label.destroy();
541
+ }
542
+ }
543
+ });
544
+ };
473
545
 
474
- // Left - up
475
- x = points[i].chartX - bBox.width - labelDistance;
476
- y = points[i].chartY - bBox.height - labelDistance;
477
- if (insidePane(x, y, bBox)) {
478
- best = series.checkClearPoint(
479
- x,
480
- y,
481
- bBox
482
- );
483
- }
484
- if (best) {
485
- results.push(best);
486
- }
546
+ /**
547
+ * Prepare drawing series labels
548
+ */
549
+ function drawLabels(proceed) {
487
550
 
488
- }
551
+ var chart = this,
552
+ delay = Math.max(
553
+ H.animObject(chart.renderer.globalAnimation).duration,
554
+ 250
555
+ ),
556
+ initial = !chart.hasRendered;
489
557
 
490
- // Brute force, try all positions on the chart in a 16x16 grid
491
- if (!results.length) {
492
- for (x = paneLeft + paneWidth - bBox.width; x >= paneLeft; x -= 16) {
493
- for (y = paneTop; y < paneTop + paneHeight - bBox.height; y += 16) {
494
- clearPoint = series.checkClearPoint(x, y, bBox, true);
495
- if (clearPoint) {
496
- results.push(clearPoint);
497
- }
498
- }
499
- }
500
- }
558
+ proceed.apply(chart, [].slice.call(arguments, 1));
501
559
 
502
- if (results.length) {
560
+ chart.labelSeries = [];
503
561
 
504
- results.sort(function(a, b) {
505
- return b.weight - a.weight;
506
- });
562
+ clearTimeout(chart.seriesLabelTimer);
507
563
 
508
- best = results[0];
564
+ // Which series should have labels
565
+ each(chart.series, function(series) {
566
+ var options = series.options.label,
567
+ label = series.labelBySeries,
568
+ closest = label && label.closest;
569
+
570
+ if (options.enabled && series.visible && (series.graph || series.area)) {
571
+ chart.labelSeries.push(series);
572
+
573
+ // The labels are processing heavy, wait until the animation is done
574
+ if (initial) {
575
+ delay = Math.max(
576
+ delay,
577
+ H.animObject(series.options.animation).duration
578
+ );
579
+ }
509
580
 
510
- chart.boxesToAvoid.push({
511
- left: best.x,
512
- right: best.x + bBox.width,
513
- top: best.y,
514
- bottom: best.y + bBox.height
581
+ // Keep the position updated to the axis while redrawing
582
+ if (closest) {
583
+ if (closest[0].plotX !== undefined) {
584
+ label.animate({
585
+ x: closest[0].plotX + closest[1],
586
+ y: closest[0].plotY + closest[2]
587
+ });
588
+ } else {
589
+ label.attr({
590
+ opacity: 0
515
591
  });
516
-
517
- // Move it if needed
518
- if (Math.round(best.x) !== Math.round(series.labelBySeries.x) || Math.round(best.y) !== Math.round(series.labelBySeries.y)) {
519
- series.labelBySeries
520
- .attr({
521
- x: best.x - paneLeft,
522
- y: best.y - paneTop,
523
- anchorX: best.connectorPoint && best.connectorPoint.plotX,
524
- anchorY: best.connectorPoint && best.connectorPoint.plotY,
525
- opacity: 0
526
- })
527
- .animate({
528
- opacity: 1
529
- });
530
- }
531
-
532
- } else if (series.labelBySeries) {
533
- series.labelBySeries = series.labelBySeries.destroy();
534
592
  }
535
593
  }
536
- });
537
- }, 350);
594
+ }
595
+ });
596
+
597
+ chart.seriesLabelTimer = setTimeout(function() {
598
+ chart.drawSeriesLabels();
599
+ }, delay);
538
600
 
539
601
  }
540
602
  wrap(Chart.prototype, 'render', drawLabels);