overlapping-datalabels.src.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /**
  2. * @license Highcharts JS v5.0.6 (2016-12-07)
  3. *
  4. * (c) 2009-2016 Torstein Honsi
  5. *
  6. * License: www.highcharts.com/license
  7. */
  8. (function(factory) {
  9. if (typeof module === 'object' && module.exports) {
  10. module.exports = factory;
  11. } else {
  12. factory(Highcharts);
  13. }
  14. }(function(Highcharts) {
  15. (function(H) {
  16. /**
  17. * (c) 2009-2016 Torstein Honsi
  18. *
  19. * License: www.highcharts.com/license
  20. */
  21. 'use strict';
  22. /**
  23. * Highcharts module to hide overlapping data labels. This module is included in Highcharts.
  24. */
  25. var Chart = H.Chart,
  26. each = H.each,
  27. pick = H.pick,
  28. addEvent = H.addEvent;
  29. // Collect potensial overlapping data labels. Stack labels probably don't need to be
  30. // considered because they are usually accompanied by data labels that lie inside the columns.
  31. Chart.prototype.callbacks.push(function(chart) {
  32. function collectAndHide() {
  33. var labels = [];
  34. each(chart.series, function(series) {
  35. var dlOptions = series.options.dataLabels,
  36. collections = series.dataLabelCollections || ['dataLabel']; // Range series have two collections
  37. if ((dlOptions.enabled || series._hasPointLabels) && !dlOptions.allowOverlap && series.visible) { // #3866
  38. each(collections, function(coll) {
  39. each(series.points, function(point) {
  40. if (point[coll]) {
  41. point[coll].labelrank = pick(point.labelrank, point.shapeArgs && point.shapeArgs.height); // #4118
  42. labels.push(point[coll]);
  43. }
  44. });
  45. });
  46. }
  47. });
  48. chart.hideOverlappingLabels(labels);
  49. }
  50. // Do it now ...
  51. collectAndHide();
  52. // ... and after each chart redraw
  53. addEvent(chart, 'redraw', collectAndHide);
  54. });
  55. /**
  56. * Hide overlapping labels. Labels are moved and faded in and out on zoom to provide a smooth
  57. * visual imression.
  58. */
  59. Chart.prototype.hideOverlappingLabels = function(labels) {
  60. var len = labels.length,
  61. label,
  62. i,
  63. j,
  64. label1,
  65. label2,
  66. isIntersecting,
  67. pos1,
  68. pos2,
  69. parent1,
  70. parent2,
  71. padding,
  72. intersectRect = function(x1, y1, w1, h1, x2, y2, w2, h2) {
  73. return !(
  74. x2 > x1 + w1 ||
  75. x2 + w2 < x1 ||
  76. y2 > y1 + h1 ||
  77. y2 + h2 < y1
  78. );
  79. };
  80. // Mark with initial opacity
  81. for (i = 0; i < len; i++) {
  82. label = labels[i];
  83. if (label) {
  84. label.oldOpacity = label.opacity;
  85. label.newOpacity = 1;
  86. }
  87. }
  88. // Prevent a situation in a gradually rising slope, that each label
  89. // will hide the previous one because the previous one always has
  90. // lower rank.
  91. labels.sort(function(a, b) {
  92. return (b.labelrank || 0) - (a.labelrank || 0);
  93. });
  94. // Detect overlapping labels
  95. for (i = 0; i < len; i++) {
  96. label1 = labels[i];
  97. for (j = i + 1; j < len; ++j) {
  98. label2 = labels[j];
  99. if (label1 && label2 && label1.placed && label2.placed && label1.newOpacity !== 0 && label2.newOpacity !== 0) {
  100. pos1 = label1.alignAttr;
  101. pos2 = label2.alignAttr;
  102. parent1 = label1.parentGroup; // Different panes have different positions
  103. parent2 = label2.parentGroup;
  104. padding = 2 * (label1.box ? 0 : label1.padding); // Substract the padding if no background or border (#4333)
  105. isIntersecting = intersectRect(
  106. pos1.x + parent1.translateX,
  107. pos1.y + parent1.translateY,
  108. label1.width - padding,
  109. label1.height - padding,
  110. pos2.x + parent2.translateX,
  111. pos2.y + parent2.translateY,
  112. label2.width - padding,
  113. label2.height - padding
  114. );
  115. if (isIntersecting) {
  116. (label1.labelrank < label2.labelrank ? label1 : label2).newOpacity = 0;
  117. }
  118. }
  119. }
  120. }
  121. // Hide or show
  122. each(labels, function(label) {
  123. var complete,
  124. newOpacity;
  125. if (label) {
  126. newOpacity = label.newOpacity;
  127. if (label.oldOpacity !== newOpacity && label.placed) {
  128. // Make sure the label is completely hidden to avoid catching clicks (#4362)
  129. if (newOpacity) {
  130. label.show(true);
  131. } else {
  132. complete = function() {
  133. label.hide();
  134. };
  135. }
  136. // Animate or set the opacity
  137. label.alignAttr.opacity = newOpacity;
  138. label[label.isOld ? 'animate' : 'attr'](label.alignAttr, null, complete);
  139. }
  140. label.isOld = true;
  141. }
  142. });
  143. };
  144. }(Highcharts));
  145. }));