path-2-segments.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import getArcParams from './get-arc-params';
  2. import { isSamePoint } from './get-arc-params';
  3. import parsePath from './parse-path';
  4. // 点对称
  5. function toSymmetry(point, center) {
  6. return [center[0] + (center[0] - point[0]), center[1] + (center[1] - point[1])];
  7. }
  8. export default function getSegments(path) {
  9. path = parsePath(path);
  10. var segments = [];
  11. var currentPoint = null; // 当前图形
  12. var nextParams = null; // 下一节点的 path 参数
  13. var startMovePoint = null; // 开始 M 的点,可能会有多个
  14. var lastStartMovePointIndex = 0; // 最近一个开始点 M 的索引
  15. var count = path.length;
  16. for (var i = 0; i < count; i++) {
  17. var params = path[i];
  18. nextParams = path[i + 1];
  19. var command = params[0];
  20. // 数学定义上的参数,便于后面的计算
  21. var segment = {
  22. command: command,
  23. prePoint: currentPoint,
  24. params: params,
  25. startTangent: null,
  26. endTangent: null,
  27. };
  28. switch (command) {
  29. case 'M':
  30. startMovePoint = [params[1], params[2]];
  31. lastStartMovePointIndex = i;
  32. break;
  33. case 'A':
  34. var arcParams = getArcParams(currentPoint, params);
  35. segment['arcParams'] = arcParams;
  36. break;
  37. default:
  38. break;
  39. }
  40. if (command === 'Z') {
  41. // 有了 Z 后,当前节点从开始 M 的点开始
  42. currentPoint = startMovePoint;
  43. // 如果当前点的命令为 Z,相当于当前点为最近一个 M 点,则下一个点直接指向最近一个 M 点的下一个点
  44. nextParams = path[lastStartMovePointIndex + 1];
  45. }
  46. else {
  47. var len = params.length;
  48. currentPoint = [params[len - 2], params[len - 1]];
  49. }
  50. if (nextParams && nextParams[0] === 'Z') {
  51. // 如果下一个点的命令为 Z,则下一个点直接指向最近一个 M 点
  52. nextParams = path[lastStartMovePointIndex];
  53. if (segments[lastStartMovePointIndex]) {
  54. // 如果下一个点的命令为 Z,则最近一个 M 点的前一个点为当前点
  55. segments[lastStartMovePointIndex].prePoint = currentPoint;
  56. }
  57. }
  58. segment['currentPoint'] = currentPoint;
  59. // 如果当前点与最近一个 M 点相同,则最近一个 M 点的前一个点为当前点的前一个点
  60. if (segments[lastStartMovePointIndex] &&
  61. isSamePoint(currentPoint, segments[lastStartMovePointIndex].currentPoint)) {
  62. segments[lastStartMovePointIndex].prePoint = segment.prePoint;
  63. }
  64. var nextPoint = nextParams ? [nextParams[nextParams.length - 2], nextParams[nextParams.length - 1]] : null;
  65. segment['nextPoint'] = nextPoint;
  66. // Add startTangent and endTangent
  67. var prePoint = segment.prePoint;
  68. if (['L', 'H', 'V'].includes(command)) {
  69. segment.startTangent = [prePoint[0] - currentPoint[0], prePoint[1] - currentPoint[1]];
  70. segment.endTangent = [currentPoint[0] - prePoint[0], currentPoint[1] - prePoint[1]];
  71. }
  72. else if (command === 'Q') {
  73. // 二次贝塞尔曲线只有一个控制点
  74. var cp = [params[1], params[2]];
  75. // 二次贝塞尔曲线的终点为 currentPoint
  76. segment.startTangent = [prePoint[0] - cp[0], prePoint[1] - cp[1]];
  77. segment.endTangent = [currentPoint[0] - cp[0], currentPoint[1] - cp[1]];
  78. }
  79. else if (command === 'T') {
  80. var preSegment = segments[i - 1];
  81. var cp = toSymmetry(preSegment.currentPoint, prePoint);
  82. if (preSegment.command === 'Q') {
  83. segment.command = 'Q';
  84. segment.startTangent = [prePoint[0] - cp[0], prePoint[1] - cp[1]];
  85. segment.endTangent = [currentPoint[0] - cp[0], currentPoint[1] - cp[1]];
  86. }
  87. else {
  88. segment.command = 'TL';
  89. segment.startTangent = [prePoint[0] - currentPoint[0], prePoint[1] - currentPoint[1]];
  90. segment.endTangent = [currentPoint[0] - prePoint[0], currentPoint[1] - prePoint[1]];
  91. }
  92. }
  93. else if (command === 'C') {
  94. // 三次贝塞尔曲线有两个控制点
  95. var cp1 = [params[1], params[2]];
  96. var cp2 = [params[3], params[4]];
  97. segment.startTangent = [prePoint[0] - cp1[0], prePoint[1] - cp1[1]];
  98. segment.endTangent = [currentPoint[0] - cp2[0], currentPoint[1] - cp2[1]];
  99. // horizontal line, eg. ['C', 100, 100, 100, 100, 200, 200]
  100. if (segment.startTangent[0] === 0 && segment.startTangent[1] === 0) {
  101. segment.startTangent = [cp1[0] - cp2[0], cp1[1] - cp2[1]];
  102. }
  103. if (segment.endTangent[0] === 0 && segment.endTangent[1] === 0) {
  104. segment.endTangent = [cp2[0] - cp1[0], cp2[1] - cp1[1]];
  105. }
  106. }
  107. else if (command === 'S') {
  108. var preSegment = segments[i - 1];
  109. var cp1 = toSymmetry(preSegment.currentPoint, prePoint);
  110. var cp2 = [params[1], params[2]];
  111. if (preSegment.command === 'C') {
  112. segment.command = 'C'; // 将 S 命令变换为 C 命令
  113. segment.startTangent = [prePoint[0] - cp1[0], prePoint[1] - cp1[1]];
  114. segment.endTangent = [currentPoint[0] - cp2[0], currentPoint[1] - cp2[1]];
  115. }
  116. else {
  117. segment.command = 'SQ'; // 将 S 命令变换为 SQ 命令
  118. segment.startTangent = [prePoint[0] - cp2[0], prePoint[1] - cp2[1]];
  119. segment.endTangent = [currentPoint[0] - cp2[0], currentPoint[1] - cp2[1]];
  120. }
  121. }
  122. else if (command === 'A') {
  123. var d = 0.001;
  124. var _a = segment['arcParams'] || {}, _b = _a.cx, cx = _b === void 0 ? 0 : _b, _c = _a.cy, cy = _c === void 0 ? 0 : _c, _d = _a.rx, rx = _d === void 0 ? 0 : _d, _e = _a.ry, ry = _e === void 0 ? 0 : _e, _f = _a.sweepFlag, sweepFlag = _f === void 0 ? 0 : _f, _g = _a.startAngle, startAngle = _g === void 0 ? 0 : _g, _h = _a.endAngle, endAngle = _h === void 0 ? 0 : _h;
  125. if (sweepFlag === 0) {
  126. d *= -1;
  127. }
  128. var dx1 = rx * Math.cos(startAngle - d) + cx;
  129. var dy1 = ry * Math.sin(startAngle - d) + cy;
  130. segment.startTangent = [dx1 - startMovePoint[0], dy1 - startMovePoint[1]];
  131. var dx2 = rx * Math.cos(startAngle + endAngle + d) + cx;
  132. var dy2 = ry * Math.sin(startAngle + endAngle - d) + cy;
  133. segment.endTangent = [prePoint[0] - dx2, prePoint[1] - dy2];
  134. }
  135. segments.push(segment);
  136. }
  137. return segments;
  138. }
  139. //# sourceMappingURL=path-2-segments.js.map