/** * @license Highcharts JS v5.0.2 (2016-10-26) * * (c) 2009-2016 Torstein Honsi * * License: www.highcharts.com/license */ (function(factory) { if (typeof module === 'object' && module.exports) { module.exports = factory; } else { factory(Highcharts); } }(function(Highcharts) { (function(H) { /** * (c) 2009-2016 Torstein Honsi * * License: www.highcharts.com/license */ 'use strict'; /** * Highcharts module to hide overlapping data labels. This module is included in Highcharts. */ var Chart = H.Chart, each = H.each, pick = H.pick, addEvent = H.addEvent; // Collect potensial overlapping data labels. Stack labels probably don't need to be // considered because they are usually accompanied by data labels that lie inside the columns. Chart.prototype.callbacks.push(function(chart) { function collectAndHide() { var labels = []; each(chart.series, function(series) { var dlOptions = series.options.dataLabels, collections = series.dataLabelCollections || ['dataLabel']; // Range series have two collections if ((dlOptions.enabled || series._hasPointLabels) && !dlOptions.allowOverlap && series.visible) { // #3866 each(collections, function(coll) { each(series.points, function(point) { if (point[coll]) { point[coll].labelrank = pick(point.labelrank, point.shapeArgs && point.shapeArgs.height); // #4118 labels.push(point[coll]); } }); }); } }); chart.hideOverlappingLabels(labels); } // Do it now ... collectAndHide(); // ... and after each chart redraw addEvent(chart, 'redraw', collectAndHide); }); /** * Hide overlapping labels. Labels are moved and faded in and out on zoom to provide a smooth * visual imression. */ Chart.prototype.hideOverlappingLabels = function(labels) { var len = labels.length, label, i, j, label1, label2, isIntersecting, pos1, pos2, parent1, parent2, padding, intersectRect = function(x1, y1, w1, h1, x2, y2, w2, h2) { return !( x2 > x1 + w1 || x2 + w2 < x1 || y2 > y1 + h1 || y2 + h2 < y1 ); }; // Mark with initial opacity for (i = 0; i < len; i++) { label = labels[i]; if (label) { label.oldOpacity = label.opacity; label.newOpacity = 1; } } // Prevent a situation in a gradually rising slope, that each label // will hide the previous one because the previous one always has // lower rank. labels.sort(function(a, b) { return (b.labelrank || 0) - (a.labelrank || 0); }); // Detect overlapping labels for (i = 0; i < len; i++) { label1 = labels[i]; for (j = i + 1; j < len; ++j) { label2 = labels[j]; if (label1 && label2 && label1.placed && label2.placed && label1.newOpacity !== 0 && label2.newOpacity !== 0) { pos1 = label1.alignAttr; pos2 = label2.alignAttr; parent1 = label1.parentGroup; // Different panes have different positions parent2 = label2.parentGroup; padding = 2 * (label1.box ? 0 : label1.padding); // Substract the padding if no background or border (#4333) isIntersecting = intersectRect( pos1.x + parent1.translateX, pos1.y + parent1.translateY, label1.width - padding, label1.height - padding, pos2.x + parent2.translateX, pos2.y + parent2.translateY, label2.width - padding, label2.height - padding ); if (isIntersecting) { (label1.labelrank < label2.labelrank ? label1 : label2).newOpacity = 0; } } } } // Hide or show each(labels, function(label) { var complete, newOpacity; if (label) { newOpacity = label.newOpacity; if (label.oldOpacity !== newOpacity && label.placed) { // Make sure the label is completely hidden to avoid catching clicks (#4362) if (newOpacity) { label.show(true); } else { complete = function() { label.hide(); }; } // Animate or set the opacity label.alignAttr.opacity = newOpacity; label[label.isOld ? 'animate' : 'attr'](label.alignAttr, null, complete); } label.isOld = true; } }); }; }(Highcharts)); }));