path.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var g_math_1 = require("@antv/g-math");
  4. var path_util_1 = require("@antv/path-util");
  5. var util_1 = require("@antv/util");
  6. var util_2 = require("./util");
  7. function getPathBox(segments, lineWidth) {
  8. var xArr = [];
  9. var yArr = [];
  10. var segmentsWithAngle = [];
  11. for (var i = 0; i < segments.length; i++) {
  12. var segment = segments[i];
  13. var currentPoint = segment.currentPoint, params = segment.params, prePoint = segment.prePoint;
  14. var box = void 0;
  15. switch (segment.command) {
  16. case 'Q':
  17. box = g_math_1.Quad.box(prePoint[0], prePoint[1], params[1], params[2], params[3], params[4]);
  18. break;
  19. case 'C':
  20. box = g_math_1.Cubic.box(prePoint[0], prePoint[1], params[1], params[2], params[3], params[4], params[5], params[6]);
  21. break;
  22. case 'A':
  23. var arcParams = segment.arcParams;
  24. box = g_math_1.Arc.box(arcParams.cx, arcParams.cy, arcParams.rx, arcParams.ry, arcParams.xRotation, arcParams.startAngle, arcParams.endAngle);
  25. break;
  26. default:
  27. xArr.push(currentPoint[0]);
  28. yArr.push(currentPoint[1]);
  29. break;
  30. }
  31. if (box) {
  32. segment.box = box;
  33. xArr.push(box.x, box.x + box.width);
  34. yArr.push(box.y, box.y + box.height);
  35. }
  36. if (lineWidth && (segment.command === 'L' || segment.command === 'M') && segment.prePoint && segment.nextPoint) {
  37. segmentsWithAngle.push(segment);
  38. }
  39. }
  40. // bbox calculation should ignore NaN for path attribute
  41. // ref: https://github.com/antvis/g/issues/210
  42. // ref: https://github.com/antvis/G2/issues/3109
  43. xArr = xArr.filter(function (item) { return !Number.isNaN(item) && item !== Infinity && item !== -Infinity; });
  44. yArr = yArr.filter(function (item) { return !Number.isNaN(item) && item !== Infinity && item !== -Infinity; });
  45. var minX = util_1.min(xArr);
  46. var minY = util_1.min(yArr);
  47. var maxX = util_1.max(xArr);
  48. var maxY = util_1.max(yArr);
  49. if (segmentsWithAngle.length === 0) {
  50. return {
  51. x: minX,
  52. y: minY,
  53. width: maxX - minX,
  54. height: maxY - minY,
  55. };
  56. }
  57. for (var i = 0; i < segmentsWithAngle.length; i++) {
  58. var segment = segmentsWithAngle[i];
  59. var currentPoint = segment.currentPoint;
  60. var extra = void 0;
  61. if (currentPoint[0] === minX) {
  62. extra = getExtraFromSegmentWithAngle(segment, lineWidth);
  63. minX = minX - extra.xExtra;
  64. }
  65. else if (currentPoint[0] === maxX) {
  66. extra = getExtraFromSegmentWithAngle(segment, lineWidth);
  67. maxX = maxX + extra.xExtra;
  68. }
  69. if (currentPoint[1] === minY) {
  70. extra = getExtraFromSegmentWithAngle(segment, lineWidth);
  71. minY = minY - extra.yExtra;
  72. }
  73. else if (currentPoint[1] === maxY) {
  74. extra = getExtraFromSegmentWithAngle(segment, lineWidth);
  75. maxY = maxY + extra.yExtra;
  76. }
  77. }
  78. return {
  79. x: minX,
  80. y: minY,
  81. width: maxX - minX,
  82. height: maxY - minY,
  83. };
  84. }
  85. function getExtraFromSegmentWithAngle(segment, lineWidth) {
  86. var prePoint = segment.prePoint, currentPoint = segment.currentPoint, nextPoint = segment.nextPoint;
  87. var currentAndPre = Math.pow(currentPoint[0] - prePoint[0], 2) + Math.pow(currentPoint[1] - prePoint[1], 2);
  88. var currentAndNext = Math.pow(currentPoint[0] - nextPoint[0], 2) + Math.pow(currentPoint[1] - nextPoint[1], 2);
  89. var preAndNext = Math.pow(prePoint[0] - nextPoint[0], 2) + Math.pow(prePoint[1] - nextPoint[1], 2);
  90. // 以 currentPoint 为顶点的夹角
  91. var currentAngle = Math.acos((currentAndPre + currentAndNext - preAndNext) / (2 * Math.sqrt(currentAndPre) * Math.sqrt(currentAndNext)));
  92. // 夹角为空、 0 或 PI 时,不需要计算夹角处的额外宽度
  93. // 注意: 由于计算精度问题,夹角为 0 的情况计算出来的角度可能是一个很小的值,还需要判断其与 0 是否近似相等
  94. if (!currentAngle || Math.sin(currentAngle) === 0 || util_1.isNumberEqual(currentAngle, 0)) {
  95. return {
  96. xExtra: 0,
  97. yExtra: 0,
  98. };
  99. }
  100. var xAngle = Math.abs(Math.atan2(nextPoint[1] - currentPoint[1], nextPoint[0] - currentPoint[0]));
  101. var yAngle = Math.abs(Math.atan2(nextPoint[0] - currentPoint[0], nextPoint[1] - currentPoint[1]));
  102. // 将夹角转为锐角
  103. xAngle = xAngle > Math.PI / 2 ? Math.PI - xAngle : xAngle;
  104. yAngle = yAngle > Math.PI / 2 ? Math.PI - yAngle : yAngle;
  105. // 这里不考虑在水平和垂直方向的投影,直接使用最大差值
  106. // 由于上层统一加减了二分之一线宽,这里需要进行弥补
  107. var extra = {
  108. // 水平方向投影
  109. xExtra: Math.cos(currentAngle / 2 - xAngle) * ((lineWidth / 2) * (1 / Math.sin(currentAngle / 2))) - lineWidth / 2 || 0,
  110. // 垂直方向投影
  111. yExtra: Math.cos(yAngle - currentAngle / 2) * ((lineWidth / 2) * (1 / Math.sin(currentAngle / 2))) - lineWidth / 2 || 0,
  112. };
  113. return extra;
  114. }
  115. function default_1(shape) {
  116. var attrs = shape.attr();
  117. var path = attrs.path, stroke = attrs.stroke;
  118. var lineWidth = stroke ? attrs.lineWidth : 0; // 只有有 stroke 时,lineWidth 才生效
  119. var segments = shape.get('segments') || path_util_1.path2Segments(path);
  120. var _a = getPathBox(segments, lineWidth), x = _a.x, y = _a.y, width = _a.width, height = _a.height;
  121. var bbox = {
  122. minX: x,
  123. minY: y,
  124. maxX: x + width,
  125. maxY: y + height,
  126. };
  127. bbox = util_2.mergeArrowBBox(shape, bbox);
  128. return {
  129. x: bbox.minX,
  130. y: bbox.minY,
  131. width: bbox.maxX - bbox.minX,
  132. height: bbox.maxY - bbox.minY,
  133. };
  134. }
  135. exports.default = default_1;
  136. //# sourceMappingURL=path.js.map