auto-hide.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. import { getMaxLabelWidth } from '../../util/label';
  2. import { getAngleByMatrix } from '../../util/matrix';
  3. import { near } from '../../util/util';
  4. // 文本是否旋转
  5. function isRotate(label) {
  6. var matrix = label.attr('matrix');
  7. return matrix && matrix[0] !== 1; // 仅在这个场景下判定
  8. }
  9. function getRotateAngle(label) {
  10. var angle = isRotate(label) ? getAngleByMatrix(label.attr('matrix')) : 0;
  11. return angle % 360;
  12. }
  13. // autohide 不再考虑超出限制
  14. // function isOutLimit(isVertical: boolean, label: IElement, limitLength: number) {
  15. // if (!limitLength) {
  16. // // 如果没限制 limitLength 则直接返回 false
  17. // return false;
  18. // }
  19. // const canvasBBox = label.getCanvasBBox();
  20. // let isOut = false;
  21. // if (isVertical) {
  22. // isOut = canvasBBox.width > limitLength;
  23. // } else {
  24. // isOut = canvasBBox.height > limitLength;
  25. // }
  26. // return isOut;
  27. // }
  28. // 是否重叠
  29. function isOverlap(isVertical, first, second, minGap) {
  30. var overlap = false;
  31. var angle = getRotateAngle(first);
  32. var distance = isVertical
  33. ? Math.abs(second.attr('y') - first.attr('y'))
  34. : Math.abs(second.attr('x') - first.attr('x'));
  35. var prevBBox = (isVertical
  36. ? second.attr('y') > first.attr('y')
  37. : second.attr('x') > first.attr('x'))
  38. ? first.getBBox()
  39. : second.getBBox();
  40. if (isVertical) {
  41. var ratio = Math.abs(Math.cos(angle));
  42. if (near(ratio, 0, Math.PI / 180)) {
  43. overlap = prevBBox.width + minGap > distance;
  44. }
  45. else {
  46. overlap = prevBBox.height / ratio + minGap > distance;
  47. }
  48. }
  49. else {
  50. var ratio = Math.abs(Math.sin(angle));
  51. if (near(ratio, 0, Math.PI / 180)) {
  52. overlap = prevBBox.width + minGap > distance;
  53. }
  54. else {
  55. overlap = prevBBox.height / ratio + minGap > distance;
  56. }
  57. }
  58. return overlap;
  59. }
  60. // 保留第一个或者最后一个
  61. function reserveOne(isVertical, labelsGroup, reversed, autoHideCfg) {
  62. var minGap = (autoHideCfg === null || autoHideCfg === void 0 ? void 0 : autoHideCfg.minGap) || 0;
  63. var labels = labelsGroup
  64. .getChildren()
  65. .slice() // 复制数组
  66. .filter(function (item) { return item.get('visible'); });
  67. if (!labels.length) {
  68. return false;
  69. }
  70. var hasHide = false;
  71. if (reversed) {
  72. // 翻转
  73. labels.reverse();
  74. }
  75. var count = labels.length;
  76. var first = labels[0];
  77. var prev = first;
  78. for (var i = 1; i < count; i++) {
  79. var label = labels[i];
  80. var curBBox = label.getBBox();
  81. // 不再考虑超出限制,而仅仅根据是否重叠进行隐藏 isOutLimit(isVertical, label, limitLength) ||
  82. var isHide = isOverlap(isVertical, prev, label, minGap);
  83. if (isHide) {
  84. label.hide();
  85. hasHide = true;
  86. }
  87. else {
  88. prev = label;
  89. }
  90. }
  91. return hasHide;
  92. }
  93. // 均匀抽样隐藏标签,注意这里假设 label/tick 是均匀的
  94. function parityHide(isVertical, labelsGroup, autoHideCfg) {
  95. var minGap = (autoHideCfg === null || autoHideCfg === void 0 ? void 0 : autoHideCfg.minGap) || 0;
  96. var labels = labelsGroup.getChildren().slice(); // 复制数组
  97. if (labels.length < 2) {
  98. // 如果数量小于 2 则直接返回,等于 2 时可能也会重合
  99. return false;
  100. }
  101. var hasHide = false;
  102. var first = labels[0];
  103. var firstBBox = first.getBBox();
  104. var second = labels[1];
  105. var count = labels.length;
  106. var angle = getRotateAngle(first);
  107. var distance = isVertical
  108. ? Math.abs(second.attr('y') - first.attr('y'))
  109. : Math.abs(second.attr('x') - first.attr('x'));
  110. var interval = 0; // 不重叠的坐标文本间距个数
  111. if (isVertical) {
  112. // 垂直的坐标轴计算垂直方向的间距
  113. var ratio = Math.abs(Math.cos(angle));
  114. if (near(ratio, 0, Math.PI / 180)) {
  115. var maxWidth = getMaxLabelWidth(labels);
  116. interval = (maxWidth + minGap) / distance;
  117. }
  118. else {
  119. interval = (firstBBox.height / ratio + minGap) / distance;
  120. }
  121. }
  122. else {
  123. // 水平坐标轴
  124. var ratio = Math.abs(Math.sin(angle));
  125. if (near(ratio, 0, Math.PI / 180)) {
  126. var maxWidth = getMaxLabelWidth(labels);
  127. interval = (maxWidth + minGap) / distance;
  128. }
  129. else {
  130. interval = (firstBBox.height / ratio + minGap) / distance;
  131. }
  132. }
  133. // interval > 1 时需要对 label 进行隐藏
  134. if (interval > 1) {
  135. interval = Math.ceil(interval);
  136. for (var i = 0; i < count; i++) {
  137. if (i % interval !== 0) {
  138. // 仅保留被整除的 label
  139. labels[i].hide();
  140. hasHide = true;
  141. }
  142. }
  143. }
  144. return hasHide;
  145. }
  146. export function getDefault() {
  147. return equidistance;
  148. }
  149. /**
  150. * 保证首个 label 可见,即使超过 limitLength 也不隐藏
  151. * @param {boolean} isVertical 是否垂直
  152. * @param {IGroup} labelsGroup label 的分组
  153. * @param {number} limitLength 另一个方向的长度限制,autoHide 不关心
  154. * @param {AxisLabelAutoHideCfg} autoHideCfg autoHide overlap 的可选配置参数
  155. */
  156. export function reserveFirst(isVertical, labelsGroup, limitLength, autoHideCfg) {
  157. return reserveOne(isVertical, labelsGroup, false, autoHideCfg);
  158. }
  159. /**
  160. * 保证最后一个 label 可见,即使超过 limitLength 也不隐藏
  161. * @param {boolean} isVertical 是否垂直
  162. * @param {IGroup} labelsGroup label 的分组
  163. * @param {number} limitLength 另一个方向的长度限制,autoHide 不关心
  164. * @param {AxisLabelAutoHideCfg} autoHideCfg autoHide overlap 的可选配置参数
  165. */
  166. export function reserveLast(isVertical, labelsGroup, limitLength, autoHideCfg) {
  167. return reserveOne(isVertical, labelsGroup, true, autoHideCfg);
  168. }
  169. /**
  170. * 保证第一个最后一个 label 可见,即使超过 limitLength 也不隐藏
  171. * @param {boolean} isVertical 是否垂直
  172. * @param {IGroup} labelsGroup label 的分组
  173. * @param {number} limitLength 另一个方向的长度限制,autoHide 不关心
  174. * @param {AxisLabelAutoHideCfg} autoHideCfg autoHide overlap 的可选配置参数
  175. */
  176. export function reserveBoth(isVertical, labelsGroup, limitLength, autoHideCfg) {
  177. var minGap = (autoHideCfg === null || autoHideCfg === void 0 ? void 0 : autoHideCfg.minGap) || 0;
  178. var labels = labelsGroup.getChildren().slice(); // 复制数组
  179. if (labels.length <= 2) {
  180. // 如果数量小于或等于 2 则直接返回
  181. return false;
  182. }
  183. var hasHide = false;
  184. var count = labels.length;
  185. var first = labels[0];
  186. var last = labels[count - 1];
  187. var preLabel = first;
  188. // 按照先保存第一个的逻辑循环一遍,最后一个不参与循环
  189. for (var i = 1; i < count - 1; i++) {
  190. var label = labels[i];
  191. var curBBox = label.getBBox();
  192. // 废弃 isOutLimit(isVertical, label, limitLength) ||
  193. var isHide = isOverlap(isVertical, preLabel, label, minGap);
  194. if (isHide) {
  195. label.hide();
  196. hasHide = true;
  197. }
  198. else {
  199. preLabel = label;
  200. }
  201. }
  202. var overlap = isOverlap(isVertical, preLabel, last, minGap);
  203. if (overlap) {
  204. // 发生冲突,则隐藏前一个保留后一个
  205. preLabel.hide();
  206. hasHide = true;
  207. }
  208. return hasHide;
  209. }
  210. /**
  211. * 保证 label 均匀显示 和 不出现重叠,主要解决文本层叠的问题,对于 limitLength 不处理
  212. * @param {boolean} isVertical 是否垂直
  213. * @param {IGroup} labelsGroup label 的分组
  214. * @param {number} limitLength 另一个方向的长度限制,autoHide 不关心
  215. * @param {AxisLabelAutoHideCfg} autoHideCfg autoHide overlap 的可选配置参数
  216. */
  217. export function equidistance(isVertical, labelsGroup, limitLength, autoHideCfg) {
  218. var hasHide = parityHide(isVertical, labelsGroup, autoHideCfg);
  219. // 处理 timeCat 类型的 tick,在均匀的基础上,再次检查出现重叠的进行隐藏
  220. if (reserveOne(isVertical, labelsGroup, false)) {
  221. hasHide = true;
  222. }
  223. return hasHide;
  224. }
  225. /**
  226. * 同 equidistance, 首先会保证 labels 均匀显示,然后会保留首尾
  227. * @param isVertical
  228. * @param labelsGroup
  229. * @param {number} limitLength 另一个方向的长度限制,autoHide 不关心
  230. * @param {AxisLabelAutoHideCfg} autoHideCfg autoHide overlap 的可选配置参数
  231. */
  232. export function equidistanceWithReverseBoth(isVertical, labelsGroup, limitLength, autoHideCfg) {
  233. var labels = labelsGroup.getChildren().slice(); // 复制数组
  234. var hasHide = parityHide(isVertical, labelsGroup, autoHideCfg);
  235. if (labels.length > 2) {
  236. var first = labels[0];
  237. var last = labels[labels.length - 1];
  238. // 如果第一个被隐藏了
  239. if (!first.get('visible')) {
  240. first.show();
  241. if (reserveOne(isVertical, labelsGroup, false, autoHideCfg)) {
  242. hasHide = true;
  243. }
  244. }
  245. // 如果最后一个被隐藏了
  246. if (!last.get('visible')) {
  247. last.show();
  248. if (reserveOne(isVertical, labelsGroup, true, autoHideCfg)) {
  249. hasHide = true;
  250. }
  251. }
  252. }
  253. return hasHide;
  254. }
  255. //# sourceMappingURL=auto-hide.js.map