labelLayout.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. var textContain = require("zrender/lib/contain/text");
  2. // FIXME emphasis label position is not same with normal label position
  3. function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
  4. list.sort(function (a, b) {
  5. return a.y - b.y;
  6. }); // 压
  7. function shiftDown(start, end, delta, dir) {
  8. for (var j = start; j < end; j++) {
  9. list[j].y += delta;
  10. if (j > start && j + 1 < end && list[j + 1].y > list[j].y + list[j].height) {
  11. shiftUp(j, delta / 2);
  12. return;
  13. }
  14. }
  15. shiftUp(end - 1, delta / 2);
  16. } // 弹
  17. function shiftUp(end, delta) {
  18. for (var j = end; j >= 0; j--) {
  19. list[j].y -= delta;
  20. if (j > 0 && list[j].y > list[j - 1].y + list[j - 1].height) {
  21. break;
  22. }
  23. }
  24. }
  25. function changeX(list, isDownList, cx, cy, r, dir) {
  26. var lastDeltaX = dir > 0 ? isDownList // 右侧
  27. ? Number.MAX_VALUE // 下
  28. : 0 // 上
  29. : isDownList // 左侧
  30. ? Number.MAX_VALUE // 下
  31. : 0; // 上
  32. for (var i = 0, l = list.length; i < l; i++) {
  33. // Not change x for center label
  34. if (list[i].position === 'center') {
  35. continue;
  36. }
  37. var deltaY = Math.abs(list[i].y - cy);
  38. var length = list[i].len;
  39. var length2 = list[i].len2;
  40. var deltaX = deltaY < r + length ? Math.sqrt((r + length + length2) * (r + length + length2) - deltaY * deltaY) : Math.abs(list[i].x - cx);
  41. if (isDownList && deltaX >= lastDeltaX) {
  42. // 右下,左下
  43. deltaX = lastDeltaX - 10;
  44. }
  45. if (!isDownList && deltaX <= lastDeltaX) {
  46. // 右上,左上
  47. deltaX = lastDeltaX + 10;
  48. }
  49. list[i].x = cx + deltaX * dir;
  50. lastDeltaX = deltaX;
  51. }
  52. }
  53. var lastY = 0;
  54. var delta;
  55. var len = list.length;
  56. var upList = [];
  57. var downList = [];
  58. for (var i = 0; i < len; i++) {
  59. delta = list[i].y - lastY;
  60. if (delta < 0) {
  61. shiftDown(i, len, -delta, dir);
  62. }
  63. lastY = list[i].y + list[i].height;
  64. }
  65. if (viewHeight - lastY < 0) {
  66. shiftUp(len - 1, lastY - viewHeight);
  67. }
  68. for (var i = 0; i < len; i++) {
  69. if (list[i].y >= cy) {
  70. downList.push(list[i]);
  71. } else {
  72. upList.push(list[i]);
  73. }
  74. }
  75. changeX(upList, false, cx, cy, r, dir);
  76. changeX(downList, true, cx, cy, r, dir);
  77. }
  78. function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {
  79. var leftList = [];
  80. var rightList = [];
  81. for (var i = 0; i < labelLayoutList.length; i++) {
  82. if (labelLayoutList[i].x < cx) {
  83. leftList.push(labelLayoutList[i]);
  84. } else {
  85. rightList.push(labelLayoutList[i]);
  86. }
  87. }
  88. adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);
  89. adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);
  90. for (var i = 0; i < labelLayoutList.length; i++) {
  91. var linePoints = labelLayoutList[i].linePoints;
  92. if (linePoints) {
  93. var dist = linePoints[1][0] - linePoints[2][0];
  94. if (labelLayoutList[i].x < cx) {
  95. linePoints[2][0] = labelLayoutList[i].x + 3;
  96. } else {
  97. linePoints[2][0] = labelLayoutList[i].x - 3;
  98. }
  99. linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;
  100. linePoints[1][0] = linePoints[2][0] + dist;
  101. }
  102. }
  103. }
  104. function _default(seriesModel, r, viewWidth, viewHeight) {
  105. var data = seriesModel.getData();
  106. var labelLayoutList = [];
  107. var cx;
  108. var cy;
  109. var hasLabelRotate = false;
  110. data.each(function (idx) {
  111. var layout = data.getItemLayout(idx);
  112. var itemModel = data.getItemModel(idx);
  113. var labelModel = itemModel.getModel('label.normal'); // Use position in normal or emphasis
  114. var labelPosition = labelModel.get('position') || itemModel.get('label.emphasis.position');
  115. var labelLineModel = itemModel.getModel('labelLine.normal');
  116. var labelLineLen = labelLineModel.get('length');
  117. var labelLineLen2 = labelLineModel.get('length2');
  118. var midAngle = (layout.startAngle + layout.endAngle) / 2;
  119. var dx = Math.cos(midAngle);
  120. var dy = Math.sin(midAngle);
  121. var textX;
  122. var textY;
  123. var linePoints;
  124. var textAlign;
  125. cx = layout.cx;
  126. cy = layout.cy;
  127. var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';
  128. if (labelPosition === 'center') {
  129. textX = layout.cx;
  130. textY = layout.cy;
  131. textAlign = 'center';
  132. } else {
  133. var x1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dx : layout.r * dx) + cx;
  134. var y1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dy : layout.r * dy) + cy;
  135. textX = x1 + dx * 3;
  136. textY = y1 + dy * 3;
  137. if (!isLabelInside) {
  138. // For roseType
  139. var x2 = x1 + dx * (labelLineLen + r - layout.r);
  140. var y2 = y1 + dy * (labelLineLen + r - layout.r);
  141. var x3 = x2 + (dx < 0 ? -1 : 1) * labelLineLen2;
  142. var y3 = y2;
  143. textX = x3 + (dx < 0 ? -5 : 5);
  144. textY = y3;
  145. linePoints = [[x1, y1], [x2, y2], [x3, y3]];
  146. }
  147. textAlign = isLabelInside ? 'center' : dx > 0 ? 'left' : 'right';
  148. }
  149. var font = labelModel.getFont();
  150. var labelRotate = labelModel.get('rotate') ? dx < 0 ? -midAngle + Math.PI : -midAngle : 0;
  151. var text = seriesModel.getFormattedLabel(idx, 'normal') || data.getName(idx);
  152. var textRect = textContain.getBoundingRect(text, font, textAlign, 'top');
  153. hasLabelRotate = !!labelRotate;
  154. layout.label = {
  155. x: textX,
  156. y: textY,
  157. position: labelPosition,
  158. height: textRect.height,
  159. len: labelLineLen,
  160. len2: labelLineLen2,
  161. linePoints: linePoints,
  162. textAlign: textAlign,
  163. verticalAlign: 'middle',
  164. rotation: labelRotate,
  165. inside: isLabelInside
  166. }; // Not layout the inside label
  167. if (!isLabelInside) {
  168. labelLayoutList.push(layout.label);
  169. }
  170. });
  171. if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {
  172. avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);
  173. }
  174. }
  175. module.exports = _default;