svgLines.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <template>
  2. <g class="lines-wrap">
  3. <marker
  4. id="markerArrow"
  5. markerUnits="strokeWidth"
  6. markerWidth="5"
  7. markerHeight="4"
  8. refX="6"
  9. refY="2"
  10. orient="auto"
  11. >
  12. <path d="M 0 0 L 5 2 L 0 4 z" class="trangle" />
  13. </marker>
  14. <path
  15. v-for="i in linesAttr"
  16. :key="i.id"
  17. v-bind="i"
  18. class="line"
  19. marker-end="url(#markerArrow)"
  20. />
  21. </g>
  22. </template>
  23. <script setup>
  24. import { computed } from "vue";
  25. import { countPointByPos } from "../utils/index";
  26. const props = defineProps(["nodes", "lines"]);
  27. function getTransitPoint(pos, point) {
  28. const transitSpace = 20;
  29. switch (pos) {
  30. case "left":
  31. return {
  32. cx: point.cx - transitSpace,
  33. cy: point.cy,
  34. };
  35. case "top":
  36. return {
  37. cx: point.cx,
  38. cy: point.cy - transitSpace,
  39. };
  40. case "right":
  41. return {
  42. cx: point.cx + transitSpace,
  43. cy: point.cy,
  44. };
  45. case "bottom":
  46. return {
  47. cx: point.cx,
  48. cy: point.cy + transitSpace,
  49. };
  50. default:
  51. break;
  52. }
  53. }
  54. function getAnchor(start, end) {
  55. const { point: startPoint, node: startNode, pos: startPos } = start;
  56. const { point: endPoint, node: endNode, pos: endPos } = end;
  57. let p1, p2;
  58. const space = 20;
  59. if (["left", "right"].includes(startPos)) {
  60. p1 = {
  61. cx: startPoint.cx,
  62. cy:
  63. startPoint.cy +
  64. (endPoint.cy > startPoint.cy
  65. ? startNode.size.height / 2 + 20
  66. : -(startNode.size.height / 2 + 20)),
  67. };
  68. } else {
  69. p1 = {
  70. cx:
  71. startPoint.cx +
  72. (endPoint.cx > startPoint.cx
  73. ? startNode.size.width / 2 + 20
  74. : -(startNode.size.width / 2 + 20)),
  75. cy: startPoint.cy,
  76. };
  77. }
  78. if (["left", "right"].includes(endPos)) {
  79. p2 = {
  80. cx: endPoint.cx,
  81. cy:
  82. endPoint.cy +
  83. (endPoint.cy > startPoint.cy
  84. ? -(endNode.size.height / 2 + 20)
  85. : endNode.size.height / 2 + 20),
  86. };
  87. } else {
  88. p2 = {
  89. cx:
  90. endPoint.cx +
  91. (endPoint.cx > startPoint.cx
  92. ? -(endNode.size.width / 2 + 20)
  93. : endNode.size.width / 2 + 20),
  94. cy: endPoint.cy,
  95. };
  96. }
  97. return [p1, p2];
  98. }
  99. function getCenterPoint(start, end) {
  100. const { point: startPoint, node: startNode, pos: startPos } = start;
  101. const { point: endPoint, node: endNode, pos: endPos } = end;
  102. // const [p1, p2] = getAnchor(start, end);
  103. // const points = [
  104. // startPoint,
  105. // p1,
  106. // {
  107. // cx: p1.cx,
  108. // cy: p2.cy,
  109. // },
  110. // p2,
  111. // endPoint,
  112. // ];
  113. // points.forEach((p, index) => {
  114. // if (index >= 2) {
  115. // const preP1 = points[index - 1];
  116. // const preP2 = points[index - 2];
  117. // if (preP1.cx === preP2.cx && preP1.cx === p.cx) {
  118. // preP2.cy = preP1.cy = Math.min(preP2.cy, preP1.cy, p.cy);
  119. // }
  120. // if (preP1.cy === preP2.cy && preP1.cy === p.cy) {
  121. // preP2.cx = preP1.cx = Math.min(preP2.cx, preP1.cx, p.cx);
  122. // }
  123. // }
  124. // });
  125. // return points;
  126. return [startPoint, { cx: startPoint.cx, cy: endPoint.cy }, endPoint];
  127. // const points = [];
  128. // let p1, p2;
  129. // if (["left", "right"].includes(startNode.pos)) {
  130. // p1 = {
  131. // cx: start.cx,
  132. // cy: end.cy,
  133. // };
  134. // } else {
  135. // p1 = {
  136. // cx: end.cx,
  137. // cy: start.cy,
  138. // };
  139. // }
  140. // if (["left", "right"].includes(endNode.pos)) {
  141. // p2 = {
  142. // cx: end.cx,
  143. // cy: p1.cy,
  144. // };
  145. // } else {
  146. // p2 = {
  147. // cx: p1.cx,
  148. // cy: end.cy,
  149. // };
  150. // }
  151. // if (start.cx < end.cx && endNode.pos === "right") {
  152. // const topSpace = Math.min(startNode.node.pos.y, endNode.node.pos.y) - 20;
  153. // return [
  154. // {
  155. // cx: start.cx,
  156. // cy: startNode.node.pos.cy + (end.cy - start.cy) / 2,
  157. // },
  158. // {
  159. // cx: end.cx,
  160. // cy: start.cy + (end.cy - start.cy) / 2,
  161. // },
  162. // ];
  163. // }
  164. // if (start.cy > end.cy) {
  165. // const endWidth = endNode.size.width / 2 + 20;
  166. // return [
  167. // {
  168. // cx: start.cx - endWidth,
  169. // cy: end.cy,
  170. // },
  171. // {
  172. // cx: end.cx - endWidth,
  173. // cy: end.cy,
  174. // },
  175. // ];
  176. // }
  177. // return [p1, p2];
  178. // return [
  179. // {
  180. // cx: start.cx,
  181. // cy: end.cy,
  182. // },
  183. // {
  184. // cx: start.cx,
  185. // cy: end.cy,
  186. // },
  187. // ];
  188. }
  189. const linesAttr = computed(() =>
  190. props.lines.map((line) => {
  191. const { targetId: startTargetId, pos: startPos } = line.start;
  192. const { targetId: endTargetId, pos: endPos } = line.end;
  193. const startNode = props.nodes.find((i) => i.id === startTargetId);
  194. const endNode = props.nodes.find((i) => i.id === endTargetId);
  195. const startPoint = countPointByPos(startPos, startNode.pos, startNode.size);
  196. const endPoint = countPointByPos(endPos, endNode.pos, endNode.size);
  197. const startTransitPoint = getTransitPoint(startPos, startPoint);
  198. const endTransitPoint = getTransitPoint(endPos, endPoint);
  199. const centerPoints = getCenterPoint(
  200. { node: startNode, pos: startPos, point: startTransitPoint },
  201. { node: endNode, pos: endPos, point: endTransitPoint }
  202. );
  203. return {
  204. id: `${startTargetId}-${startPos}-${endTargetId}-${endPos}`,
  205. d: [
  206. `M${startPoint.cx} ${startPoint.cy}`,
  207. ...centerPoints.map((i) => `L${i.cx} ${i.cy}`),
  208. `L${endPoint.cx} ${endPoint.cy}`,
  209. ].join(" "),
  210. };
  211. // return {
  212. // id: `${startTargetId}-${startPos}-${endTargetId}-${endPos}`,
  213. // x1: startPoint.cx,
  214. // y1: startPoint.cy,
  215. // x2: endPoint.cx,
  216. // y2: endPoint.cy,
  217. // };
  218. })
  219. );
  220. </script>
  221. <style lang="less" scoped>
  222. .lines-wrap {
  223. .line {
  224. stroke: #5ba8ff;
  225. stroke-width: 2;
  226. fill: transparent;
  227. }
  228. .trangle {
  229. stroke: #5ba8ff;
  230. fill: #5ba8ff;
  231. }
  232. }
  233. </style>