Ver código fonte

feature: 连线

xiongxt 1 ano atrás
pai
commit
1a4340e338
2 arquivos alterados com 211 adições e 26 exclusões
  1. 191 6
      src/views/svg/components/svgLines.vue
  2. 20 20
      src/views/svg/index.vue

+ 191 - 6
src/views/svg/components/svgLines.vue

@@ -11,7 +11,7 @@
     >
       <path d="M 0 0 L 5 2 L 0 4 z" class="trangle" />
     </marker>
-    <line
+    <path
       v-for="i in linesAttr"
       :key="i.id"
       v-bind="i"
@@ -26,21 +26,205 @@ import { defineProps, computed } from "vue";
 import { countPointByPos } from "../utils/index";
 const props = defineProps(["nodes", "lines"]);
 
+function getTransitPoint(pos, point) {
+  const transitSpace = 20;
+  switch (pos) {
+    case "left":
+      return {
+        cx: point.cx - transitSpace,
+        cy: point.cy,
+      };
+    case "top":
+      return {
+        cx: point.cx,
+        cy: point.cy - transitSpace,
+      };
+    case "right":
+      return {
+        cx: point.cx + transitSpace,
+        cy: point.cy,
+      };
+    case "bottom":
+      return {
+        cx: point.cx,
+        cy: point.cy + transitSpace,
+      };
+    default:
+      break;
+  }
+}
+
+function getAnchor(start, end) {
+  const { point: startPoint, node: startNode, pos: startPos } = start;
+  const { point: endPoint, node: endNode, pos: endPos } = end;
+
+  let p1, p2;
+  const space = 20;
+  if (["left", "right"].includes(startPos)) {
+    p1 = {
+      cx: startPoint.cx,
+      cy:
+        startPoint.cy +
+        (endPoint.cy > startPoint.cy
+          ? startNode.size.height / 2 + 20
+          : -(startNode.size.height / 2 + 20)),
+    };
+  } else {
+    p1 = {
+      cx:
+        startPoint.cx +
+        (endPoint.cx > startPoint.cx
+          ? startNode.size.width / 2 + 20
+          : -(startNode.size.width / 2 + 20)),
+      cy: startPoint.cy,
+    };
+  }
+  if (["left", "right"].includes(endPos)) {
+    p2 = {
+      cx: endPoint.cx,
+      cy:
+        endPoint.cy +
+        (endPoint.cy > startPoint.cy
+          ? -(endNode.size.height / 2 + 20)
+          : endNode.size.height / 2 + 20),
+    };
+  } else {
+    p2 = {
+      cx:
+        endPoint.cx +
+        (endPoint.cx > startPoint.cx
+          ? -(endNode.size.width / 2 + 20)
+          : endNode.size.width / 2 + 20),
+      cy: endPoint.cy,
+    };
+  }
+
+  return [p1, p2];
+}
+
+function getCenterPoint(start, end) {
+  const { point: startPoint, node: startNode, pos: startPos } = start;
+  const { point: endPoint, node: endNode, pos: endPos } = end;
+  // const [p1, p2] = getAnchor(start, end);
+  // const points = [
+  //   startPoint,
+  //   p1,
+  //   {
+  //     cx: p1.cx,
+  //     cy: p2.cy,
+  //   },
+  //   p2,
+  //   endPoint,
+  // ];
+
+  // points.forEach((p, index) => {
+  //   if (index >= 2) {
+  //     const preP1 = points[index - 1];
+  //     const preP2 = points[index - 2];
+  //     if (preP1.cx === preP2.cx && preP1.cx === p.cx) {
+  //       preP2.cy = preP1.cy = Math.min(preP2.cy, preP1.cy, p.cy);
+  //     }
+  //     if (preP1.cy === preP2.cy && preP1.cy === p.cy) {
+  //       preP2.cx = preP1.cx = Math.min(preP2.cx, preP1.cx, p.cx);
+  //     }
+  //   }
+  // });
+  // return points;
+  return [startPoint, { cx: startPoint.cx, cy: endPoint.cy }, endPoint];
+  // const points = [];
+  // let p1, p2;
+  // if (["left", "right"].includes(startNode.pos)) {
+  //   p1 = {
+  //     cx: start.cx,
+  //     cy: end.cy,
+  //   };
+  // } else {
+  //   p1 = {
+  //     cx: end.cx,
+  //     cy: start.cy,
+  //   };
+  // }
+  // if (["left", "right"].includes(endNode.pos)) {
+  //   p2 = {
+  //     cx: end.cx,
+  //     cy: p1.cy,
+  //   };
+  // } else {
+  //   p2 = {
+  //     cx: p1.cx,
+  //     cy: end.cy,
+  //   };
+  // }
+  // if (start.cx < end.cx && endNode.pos === "right") {
+  //   const topSpace = Math.min(startNode.node.pos.y, endNode.node.pos.y) - 20;
+  //   return [
+  //     {
+  //       cx: start.cx,
+  //       cy: startNode.node.pos.cy + (end.cy - start.cy) / 2,
+  //     },
+  //     {
+  //       cx: end.cx,
+  //       cy: start.cy + (end.cy - start.cy) / 2,
+  //     },
+  //   ];
+  // }
+  // if (start.cy > end.cy) {
+  //   const endWidth = endNode.size.width / 2 + 20;
+  //   return [
+  //     {
+  //       cx: start.cx - endWidth,
+  //       cy: end.cy,
+  //     },
+  //     {
+  //       cx: end.cx - endWidth,
+  //       cy: end.cy,
+  //     },
+  //   ];
+  // }
+  // return [p1, p2];
+  // return [
+  //   {
+  //     cx: start.cx,
+  //     cy: end.cy,
+  //   },
+  //   {
+  //     cx: start.cx,
+  //     cy: end.cy,
+  //   },
+  // ];
+}
+
 const linesAttr = computed(() =>
   props.lines.map((line) => {
     const { targetId: startTargetId, pos: startPos } = line.start;
     const { targetId: endTargetId, pos: endPos } = line.end;
     const startNode = props.nodes.find((i) => i.id === startTargetId);
     const endNode = props.nodes.find((i) => i.id === endTargetId);
-    const endPoint = countPointByPos(endPos, endNode.pos, endNode.size);
     const startPoint = countPointByPos(startPos, startNode.pos, startNode.size);
+    const endPoint = countPointByPos(endPos, endNode.pos, endNode.size);
+
+    const startTransitPoint = getTransitPoint(startPos, startPoint);
+    const endTransitPoint = getTransitPoint(endPos, endPoint);
+    const centerPoints = getCenterPoint(
+      { node: startNode, pos: startPos, point: startTransitPoint },
+      { node: endNode, pos: endPos, point: endTransitPoint }
+    );
+
     return {
       id: `${startTargetId}-${startPos}-${endTargetId}-${endPos}`,
-      x1: startPoint.cx,
-      y1: startPoint.cy,
-      x2: endPoint.cx,
-      y2: endPoint.cy,
+      d: [
+        `M${startPoint.cx} ${startPoint.cy}`,
+        ...centerPoints.map((i) => `L${i.cx} ${i.cy}`),
+        `L${endPoint.cx} ${endPoint.cy}`,
+      ].join(" "),
     };
+    // return {
+    //   id: `${startTargetId}-${startPos}-${endTargetId}-${endPos}`,
+    //   x1: startPoint.cx,
+    //   y1: startPoint.cy,
+    //   x2: endPoint.cx,
+    //   y2: endPoint.cy,
+    // };
   })
 );
 </script>
@@ -50,6 +234,7 @@ const linesAttr = computed(() =>
   .line {
     stroke: #5ba8ff;
     stroke-width: 2;
+    fill: transparent;
   }
 
   .trangle {

+ 20 - 20
src/views/svg/index.vue

@@ -57,28 +57,28 @@ const isDragging = ref(false);
 const lineStartPoint = ref(null);
 const lineEndPoint = ref(null);
 const lines = reactive([
-  { start: { targetId: 1, pos: "right" }, end: { targetId: 2, pos: "left" } },
-  { start: { targetId: 2, pos: "right" }, end: { targetId: 3, pos: "left" } },
+  // { start: { targetId: 1, pos: "right" }, end: { targetId: 2, pos: "left" } },
+  // { start: { targetId: 2, pos: "right" }, end: { targetId: 3, pos: "left" } },
 ]);
 const nodes = ref([
-  {
-    id: 1,
-    pos: { x: 200, y: 200 },
-    type: "rect",
-    size: { width: 100, height: 100 },
-  },
-  {
-    id: 2,
-    type: "rhombic",
-    pos: { x: 350, y: 210 },
-    size: { width: 120, height: 80 },
-  },
-  {
-    id: 3,
-    pos: { x: 550, y: 220 },
-    type: "circle",
-    size: { width: 60, height: 60 },
-  },
+  // {
+  //   id: 1,
+  //   pos: { x: 200, y: 200 },
+  //   type: "rect",
+  //   size: { width: 100, height: 100 },
+  // },
+  // {
+  //   id: 2,
+  //   type: "rhombic",
+  //   pos: { x: 350, y: 210 },
+  //   size: { width: 120, height: 80 },
+  // },
+  // {
+  //   id: 3,
+  //   pos: { x: 550, y: 220 },
+  //   type: "circle",
+  //   size: { width: 60, height: 60 },
+  // },
 ]);
 
 const curNode = computed(() => {