labels.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.renderLabels = void 0;
  4. var tslib_1 = require("tslib");
  5. var util_1 = require("@antv/util");
  6. var animation_1 = require("../../../animation");
  7. var util_2 = require("../../../util");
  8. var constant_1 = require("../constant");
  9. var overlap_1 = require("../overlap");
  10. var utils_1 = require("../utils");
  11. var line_1 = require("./line");
  12. var utils_2 = require("./utils");
  13. var angleNormalizer = function (angle) {
  14. var normalizedAngle = angle;
  15. while (normalizedAngle < 0)
  16. normalizedAngle += 360;
  17. return Math.round(normalizedAngle % 360);
  18. };
  19. var getAngle = (0, util_1.memoize)(function (v1, v2) {
  20. var _a = tslib_1.__read(v1, 2), x1 = _a[0], y1 = _a[1];
  21. var _b = tslib_1.__read(v2, 2), x2 = _b[0], y2 = _b[1];
  22. var _c = tslib_1.__read([x1 * x2 + y1 * y2, x1 * y2 - y1 * x2], 2), dot = _c[0], det = _c[1];
  23. return Math.atan2(det, dot);
  24. }, function (v1, v2) { return tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(v1), false), tslib_1.__read(v2), false).join(); });
  25. /** to correct label rotation to avoid inverted character */
  26. function correctLabelRotation(_rotate) {
  27. var rotate = (_rotate + 360) % 180;
  28. if (!(0, util_2.inRange)(rotate, -90, 90))
  29. rotate += 180;
  30. return rotate;
  31. }
  32. /** get rotation from preset or layout */
  33. function getLabelRotation(datum, label, attr) {
  34. var _a;
  35. var labelAlign = attr.labelAlign;
  36. // if label rotate is set, use it
  37. var customRotate = (_a = label.style.transform) === null || _a === void 0 ? void 0 : _a.includes('rotate');
  38. if (customRotate)
  39. return label.getLocalEulerAngles();
  40. var rotate = 0;
  41. var labelVector = (0, utils_2.getLabelVector)(datum.value, attr);
  42. var tangentVector = (0, utils_2.getLineTangentVector)(datum.value, attr);
  43. if (labelAlign === 'horizontal')
  44. return 0;
  45. if (labelAlign === 'perpendicular')
  46. rotate = getAngle([1, 0], labelVector);
  47. else
  48. rotate = getAngle([tangentVector[0] < 0 ? -1 : 1, 0], tangentVector);
  49. return correctLabelRotation((0, util_2.radToDeg)(rotate));
  50. }
  51. /** get the label align according to its tick and label angle */
  52. function getLabelStyle(value, rotate, attr) {
  53. var type = attr.type, labelAlign = attr.labelAlign;
  54. var labelVector = (0, utils_2.getLabelVector)(value, attr);
  55. var labelAngle = angleNormalizer(rotate);
  56. var tickAngle = angleNormalizer((0, util_2.radToDeg)(getAngle([1, 0], labelVector)));
  57. var textAlign = 'center';
  58. var textBaseline = 'middle';
  59. if (type === 'linear') {
  60. // tick 和 label 均为水平或垂直时,做快速判断
  61. if ([90, 270].includes(tickAngle) && labelAngle === 0) {
  62. textAlign = 'center';
  63. textBaseline = labelVector[1] === 1 ? 'top' : 'bottom';
  64. }
  65. else if (!(tickAngle % 180) && [90, 270].includes(labelAngle)) {
  66. textAlign = 'center';
  67. }
  68. // 根据 tick 和 label 的角度,判断 label 的对齐方式
  69. else if (tickAngle === 0) {
  70. if ((0, util_2.inRange)(labelAngle, 0, 90, false, true)) {
  71. textAlign = 'start';
  72. }
  73. else if ((0, util_2.inRange)(labelAngle, 0, 90) || (0, util_2.inRange)(labelAngle, 270, 360)) {
  74. textAlign = 'start';
  75. }
  76. }
  77. else if (tickAngle === 90) {
  78. if ((0, util_2.inRange)(labelAngle, 0, 90, false, true)) {
  79. textAlign = 'start';
  80. }
  81. else if ((0, util_2.inRange)(labelAngle, 90, 180) || (0, util_2.inRange)(labelAngle, 270, 360)) {
  82. textAlign = 'end';
  83. }
  84. }
  85. else if (tickAngle === 270) {
  86. if ((0, util_2.inRange)(labelAngle, 0, 90, false, true)) {
  87. textAlign = 'end';
  88. }
  89. else if ((0, util_2.inRange)(labelAngle, 90, 180) || (0, util_2.inRange)(labelAngle, 270, 360)) {
  90. textAlign = 'start';
  91. }
  92. }
  93. else if (tickAngle === 180) {
  94. if (labelAngle === 90) {
  95. textAlign = 'start';
  96. }
  97. else if ((0, util_2.inRange)(labelAngle, 0, 90) || (0, util_2.inRange)(labelAngle, 270, 360)) {
  98. textAlign = 'end';
  99. }
  100. }
  101. /**
  102. * todo tick 倾斜时的判断逻辑,该情况下坐标轴非垂直或水平
  103. */
  104. }
  105. else {
  106. // 弧线坐标轴 label 的对齐方式判断逻辑
  107. if (labelAlign === 'parallel') {
  108. if ((0, util_2.inRange)(tickAngle, 0, 180, true)) {
  109. textBaseline = 'top';
  110. }
  111. else {
  112. textBaseline = 'bottom';
  113. }
  114. }
  115. else if (labelAlign === 'horizontal') {
  116. if ((0, util_2.inRange)(tickAngle, 90, 270, false)) {
  117. textAlign = 'end';
  118. }
  119. else if ((0, util_2.inRange)(tickAngle, 270, 360, false) || (0, util_2.inRange)(tickAngle, 0, 90)) {
  120. textAlign = 'start';
  121. }
  122. }
  123. else if (labelAlign === 'perpendicular') {
  124. if ((0, util_2.inRange)(tickAngle, 90, 270)) {
  125. textAlign = 'end';
  126. }
  127. else {
  128. textAlign = 'start';
  129. }
  130. }
  131. }
  132. return { textAlign: textAlign, textBaseline: textBaseline };
  133. }
  134. function setRotateAndAdjustLabelAlign(rotate, group, attr) {
  135. group.setLocalEulerAngles(rotate);
  136. var value = group.__data__.value;
  137. var textStyle = getLabelStyle(value, rotate, attr);
  138. var label = group.querySelector(constant_1.CLASS_NAMES.labelItem.class);
  139. if (label)
  140. applyTextStyle(label, textStyle);
  141. }
  142. function getLabelPos(datum, data, attr) {
  143. var showTick = attr.showTick, tickLength = attr.tickLength, tickDirection = attr.tickDirection, labelDirection = attr.labelDirection, labelSpacing = attr.labelSpacing;
  144. var index = data.indexOf(datum);
  145. var finalLabelSpacing = (0, util_2.getCallbackValue)(labelSpacing, [datum, index, data]);
  146. var _a = tslib_1.__read([(0, utils_2.getLabelVector)(datum.value, attr), (0, utils_1.getFactor)(labelDirection, tickDirection)], 2), labelVector = _a[0], unionFactor = _a[1];
  147. var extraLength = unionFactor === 1 ? (0, util_2.getCallbackValue)(showTick ? tickLength : 0, [datum, index, data]) : 0;
  148. var _b = tslib_1.__read((0, util_2.add)((0, util_2.scale)(labelVector, finalLabelSpacing + extraLength), (0, line_1.getValuePos)(datum.value, attr)), 2), x = _b[0], y = _b[1];
  149. return { x: x, y: y };
  150. }
  151. function formatter(datum, index, data, attr) {
  152. var labelFormatter = attr.labelFormatter;
  153. var element = (0, util_1.isFunction)(labelFormatter)
  154. ? function () { return (0, util_2.renderExtDo)((0, util_2.getCallbackValue)(labelFormatter, [datum, index, data, (0, utils_2.getLabelVector)(datum.value, attr)])); }
  155. : function () { return (0, util_2.renderExtDo)(datum.label || ''); };
  156. return element;
  157. }
  158. function applyTextStyle(node, style) {
  159. if (node.nodeName === 'text')
  160. node.attr(style);
  161. }
  162. function overlapHandler(attr) {
  163. (0, overlap_1.processOverlap)(this.node().childNodes, attr, {
  164. hide: util_2.hide,
  165. show: util_2.show,
  166. rotate: function (label, angle) {
  167. setRotateAndAdjustLabelAlign(+angle, label, attr);
  168. },
  169. ellipsis: function (label, len, suffix) {
  170. if (len === void 0) { len = Infinity; }
  171. label && (0, util_2.ellipsisIt)(label, len, suffix);
  172. },
  173. wrap: function (label, width, lines) {
  174. label && (0, util_2.wrapIt)(label, width, lines);
  175. },
  176. getTextShape: function (label) { return label.querySelector('text'); },
  177. });
  178. }
  179. function renderLabel(container, datum, data, style, attr) {
  180. var index = data.indexOf(datum);
  181. var label = (0, util_2.select)(container)
  182. .append(formatter(datum, index, data, attr))
  183. .attr('className', constant_1.CLASS_NAMES.labelItem.name)
  184. .node();
  185. var _a = tslib_1.__read((0, util_2.splitStyle)((0, utils_2.getCallbackStyle)(style, [datum, index, data])), 2), labelStyle = _a[0], _b = _a[1], transform = _b.transform, groupStyle = tslib_1.__rest(_b, ["transform"]);
  186. (0, util_2.percentTransform)(container, transform);
  187. var rotate = getLabelRotation(datum, container, attr);
  188. container.setLocalEulerAngles(+rotate);
  189. applyTextStyle(label, tslib_1.__assign(tslib_1.__assign({}, getLabelStyle(datum.value, rotate, attr)), labelStyle));
  190. // todo G transform 存在问题,需要二次设置
  191. (0, util_2.percentTransform)(container, transform);
  192. container.attr(groupStyle);
  193. return label;
  194. }
  195. function renderLabels(container, data, attr, animate) {
  196. var finalData = (0, utils_2.filterExec)(data, attr.labelFilter);
  197. var style = (0, util_2.subStyleProps)(attr, 'label');
  198. return container
  199. .selectAll(constant_1.CLASS_NAMES.label.class)
  200. .data(finalData, function (d, i) { return i; })
  201. .join(function (enter) {
  202. return enter
  203. .append('g')
  204. .attr('className', constant_1.CLASS_NAMES.label.name)
  205. .transition(function (datum) {
  206. renderLabel(this, datum, data, style, attr);
  207. this.attr(getLabelPos(datum, data, attr));
  208. this.__bbox__ = datum.bbox;
  209. return null;
  210. })
  211. .call(function () { return overlapHandler.call(container, attr); });
  212. }, function (update) {
  213. return update
  214. .transition(function (datum) {
  215. var prevLabel = this.querySelector(constant_1.CLASS_NAMES.labelItem.class);
  216. var label = renderLabel(this, datum, data, style, attr);
  217. var shapeAnimation = (0, animation_1.transitionShape)(prevLabel, label, animate.update);
  218. var animation = (0, animation_1.transition)(this, getLabelPos(datum, data, attr), animate.update);
  219. this.__bbox__ = datum.bbox;
  220. return tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(shapeAnimation), false), [animation], false);
  221. })
  222. .call(function (selection) {
  223. var transitions = (0, util_1.get)(selection, '_transitions').flat().filter(util_2.defined);
  224. (0, animation_1.onAnimatesFinished)(transitions, function () { return overlapHandler.call(container, attr); });
  225. });
  226. }, function (exit) {
  227. return exit.transition(function () {
  228. var _this = this;
  229. var animation = (0, animation_1.fadeOut)(this, animate.exit);
  230. (0, animation_1.onAnimateFinished)(animation, function () { return (0, util_2.select)(_this).remove(); });
  231. return animation;
  232. });
  233. })
  234. .transitions();
  235. }
  236. exports.renderLabels = renderLabels;
  237. //# sourceMappingURL=labels.js.map