highcharts-rails 5.0.0 → 5.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);