Ver Fonte

feature:

xiongxt há 1 ano atrás
pai
commit
40a57568c6

+ 1 - 1
src/components/navBar.vue

@@ -4,7 +4,7 @@
       <h1>Ludash</h1>
     </div>
     <div class="menu">
-      <RouterLink to="/svg">SVG</RouterLink>
+      <RouterLink to="/flow">Flow</RouterLink>
       <RouterLink to="/install">安装</RouterLink>
       <RouterLink to="/sdk">SDK</RouterLink>
     </div>

+ 2 - 2
src/router/index.js

@@ -31,8 +31,8 @@ const routes = [
     ],
   },
   {
-    path: "/svg",
-    name: "svg",
+    path: "/flow",
+    name: "flow",
     component: defineComponent({
       name: "DynamicComponent",
       render() {

+ 118 - 63
src/views/svg/components/svgRect.vue

@@ -1,7 +1,30 @@
 <template>
-  <g @mousedown="handleMousedown" :id="id">
+  <g
+    :id="id"
+    class="wrap"
+    @mousedown="handleMousedown"
+    @mouseenter="boxMouseEnter"
+    @mouseleave="boxMouseLeave"
+  >
     <rect v-bind="outlineRectAttr" />
     <rect v-bind="attr" />
+    <marker
+      id="markerArrow"
+      markerUnits="strokeWidth"
+      markerWidth="5"
+      markerHeight="4"
+      refX="6"
+      refY="2"
+      orient="auto"
+    >
+      <path d="M 0 0 L 5 2 L 0 4 z" stroke="#5ba8ff" fill="#5ba8ff" />
+    </marker>
+    <line
+      v-for="i in linesAttr"
+      :key="i.id"
+      v-bind="i"
+      marker-end="url(#markerArrow)"
+    />
     <circle
       v-for="i in pointsAttr"
       v-bind="i"
@@ -22,19 +45,18 @@ import {
   defineEmits,
   computed,
 } from "vue";
-import { sticky } from "../utils/index";
+import { sticky, countPointByPos } from "../utils/index";
 const props = defineProps([
   "pos",
   "size",
+  "lines",
+  "allItems",
   "mousePos",
   "startPoint",
   "id",
   "draggingId",
+  "isDragging",
 ]);
-const boxPos = ref(props.pos);
-const boxSize = ref(props.size);
-const innerPos = ref({ x: 0, y: 0 });
-const isDraging = computed(() => props.id === props.draggingId);
 const emits = defineEmits([
   "startDrag",
   "startLine",
@@ -42,14 +64,19 @@ const emits = defineEmits([
   "endLine",
   "cancelEndLine",
 ]);
+const boxPos = ref(props.pos);
+const boxSize = ref(props.size);
+const innerPos = ref({ x: 0, y: 0 });
+const isFocus = computed(() => props.id === props.draggingId);
+const isHover = ref(false);
 
 const attr = computed(() => {
   return {
-    x: boxPos.value.x,
-    y: boxPos.value.y,
-    width: boxSize.value.width,
-    height: boxSize.value.height,
-    fill: "rgba(255,255,255,1)",
+    x: props.pos.x,
+    y: props.pos.y,
+    width: props.size.width,
+    height: props.size.height,
+    fill: "rgba(255,255,255,0.6)",
     stroke: "#666",
     rx: "15",
   };
@@ -58,51 +85,66 @@ const attr = computed(() => {
 const outlineRectAttr = computed(() => {
   const space = 8;
   return {
-    x: boxPos.value.x - space,
-    y: boxPos.value.y - space,
-    width: boxSize.value.width + space * 2,
-    height: boxSize.value.height + space * 2,
+    x: props.pos.x - space,
+    y: props.pos.y - space,
+    width: props.size.width + space * 2,
+    height: props.size.height + space * 2,
     fill: "rgba(255,255,255,0)",
     "stroke-dasharray": "3 4",
-    stroke: "#000",
+    stroke: isFocus.value ? "#000" : "rgba(0,0,0,0)",
     rx: "18",
   };
 });
 
-const pointsAttr = computed(() => [
-  {
-    pos: `top`,
-    cx: boxPos.value.x + boxSize.value.width / 2,
-    cy: boxPos.value.y,
-    r: 4,
-    stroke: "#000",
-    fill: "rgba(255,255,255,1)",
-  },
-  {
-    pos: `right`,
-    cx: boxPos.value.x + boxSize.value.width,
-    cy: boxPos.value.y + boxSize.value.height / 2,
-    r: 4,
-    stroke: "#000",
-    fill: "rgba(255,255,255,1)",
-  },
-  {
-    pos: `bottom`,
-    cx: boxPos.value.x + boxSize.value.width / 2,
-    cy: boxPos.value.y + boxSize.value.height,
-    r: 4,
-    stroke: "#000",
-    fill: "rgba(255,255,255,1)",
-  },
-  {
-    pos: `left`,
-    cx: boxPos.value.x,
-    cy: boxPos.value.y + boxSize.value.height / 2,
-    r: 4,
-    stroke: "#000",
-    fill: "rgba(255,255,255,1)",
-  },
-]);
+const pointsAttr = computed(() => {
+  const visible = isHover.value || isFocus.value;
+  const defaults = {
+    r: 6,
+    stroke: visible ? "#000" : "rgba(0,0,0,0)",
+    fill: visible ? "rgba(255,255,255,1)" : "rgba(255,255,255,0)",
+  };
+  return [
+    {
+      pos: "top",
+      ...countPointByPos("top", props.pos, props.size),
+      ...defaults,
+    },
+    {
+      pos: "right",
+      ...countPointByPos("right", props.pos, props.size),
+      ...defaults,
+    },
+    {
+      pos: "bottom",
+      ...countPointByPos("bottom", props.pos, props.size),
+      ...defaults,
+    },
+    {
+      pos: "left",
+      ...countPointByPos("left", props.pos, props.size),
+      ...defaults,
+    },
+  ];
+});
+
+const linesAttr = computed(() =>
+  props.lines.map((line) => {
+    const startPos = line.start.pos;
+    const { targetId, pos: endPos } = line.end;
+    const startPoint = countPointByPos(startPos, props.pos, props.size);
+    const endBox = props.allItems.find((i) => i.id === targetId);
+    const endPoint = countPointByPos(endPos, endBox.pos, endBox.size);
+    return {
+      id: `${startPos}-${targetId}-${endPos}`,
+      x1: startPoint.cx,
+      y1: startPoint.cy,
+      x2: endPoint.cx,
+      y2: endPoint.cy,
+      stroke: "#5ba8ff",
+      "stroke-width": "2",
+    };
+  })
+);
 
 function handleMousedown(e) {
   emits("startDrag", {
@@ -110,8 +152,8 @@ function handleMousedown(e) {
     event: e,
   });
   innerPos.value = {
-    x: e.offsetX - boxPos.value.x,
-    y: e.offsetY - boxPos.value.y,
+    x: e.offsetX - props.pos.x,
+    y: e.offsetY - props.pos.y,
   };
 }
 
@@ -124,8 +166,7 @@ function startLine(e, point) {
 }
 
 function pointMouseEnter(p) {
-  if (props.startPoint?.itemId !== props.id) {
-    console.log(props.startPoint);
+  if (props.startPoint?.targetId !== props.id) {
     emits("endLine", {
       point: p,
       id: props.id,
@@ -133,23 +174,33 @@ function pointMouseEnter(p) {
   }
 }
 
-function pointMouseLeave() {}
+function pointMouseLeave() {
+  emits("cancelEndLine");
+}
+
+function boxMouseEnter() {
+  emits("hover", props.id);
+  isHover.value = true;
+}
+
+function boxMouseLeave() {
+  isHover.value = false;
+}
 
 function setPos(pos) {
-  boxPos.value = {
-    x: sticky(pos.x - innerPos.value.x),
-    y: sticky(pos.y - innerPos.value.y),
-  };
   emits("updatePos", {
     id: props.id,
-    pos: boxPos.value,
+    pos: {
+      x: sticky(pos.x - innerPos.value.x),
+      y: sticky(pos.y - innerPos.value.y),
+    },
   });
 }
 
 watch(
   () => props.mousePos,
   (pos) => {
-    if (isDraging.value) {
+    if (props.isDragging && isFocus.value) {
       setPos(pos);
     }
   }
@@ -157,7 +208,11 @@ watch(
 </script>
 
 <style lang="less" scoped>
-circle {
-  cursor: pointer;
+.wrap {
+  &:hover {
+    rect {
+      fill: red;
+    }
+  }
 }
 </style>

+ 68 - 11
src/views/svg/index.vue

@@ -15,16 +15,23 @@
         v-for="i in children"
         :key="i.id"
         v-bind="i"
+        :isDragging="isDragging"
         :draggingId="draggingId"
         :mousePos="curPos"
         :startPoint="lineStartPoint"
+        :allItems="children"
         @startLine="startLine"
         @endLine="endLine"
+        @cancelEndLine="cancelEndLine"
         @startDrag="startDrag"
+        @hover="hover"
         @updatePos="updatePos"
       />
-
-      <line v-if="lineStartPoint" v-bind="dashLineAttr"></line>
+      <line
+        v-if="lineStartPoint"
+        v-bind="dashLineAttr"
+        class="dash-line"
+      ></line>
     </svg>
   </div>
 </template>
@@ -39,6 +46,7 @@ const childrenRefs = ref(null);
 let curPos = ref({ x: 0, y: 0 });
 const wrapSize = reactive({ width: 0, height: 0 });
 const draggingId = ref(0);
+const isDragging = ref(false);
 const lineStartPoint = ref(null);
 const lineEndPoint = ref(null);
 const children = ref([
@@ -52,7 +60,17 @@ const children = ref([
     id: 2,
     pos: { x: 20, y: 20 },
     size: { width: 100, height: 100 },
-    lines: [],
+    lines: [
+      {
+        start: {
+          pos: "right",
+        },
+        end: {
+          targetId: 3,
+          pos: "left",
+        },
+      },
+    ],
   },
   {
     id: 3,
@@ -69,15 +87,13 @@ const dashLineAttr = computed(() => {
       y1: lineStartPoint.value?.cy,
       x2: lineEndPoint.value?.cx ?? curPos.value.x,
       y2: lineEndPoint.value?.cy ?? curPos.value.y,
-      stroke: "black",
-      "stroke-dasharray": "3 4",
-      "stroke-width": "2",
     };
   }
   return {};
 });
 
 function startDrag({ id, event }) {
+  isDragging.value = true;
   draggingId.value = id;
   lineStartPoint.value = null;
   lineEndPoint.value = null;
@@ -87,24 +103,35 @@ function startDrag({ id, event }) {
   children.value.push(result);
 }
 
+function hover(id) {
+  // const { index, result } = findFromArray(children.value, (i) => i.id === id);
+  // children.value.splice(index, 1);
+  // children.value.push(result);
+}
+
 function startLine({ id, point }) {
-  draggingId.value = 0;
+  isDragging.value = false;
   lineStartPoint.value = {
-    itemId: id,
+    targetId: id,
     ...point,
   };
 }
 
 function endLine({ id, point }) {
   if (lineStartPoint.value) {
-    // const { index, result } = findFromArray(children, (i) => i.id === id);
     lineEndPoint.value = {
-      itemId: id,
+      targetId: id,
       ...point,
     };
   }
 }
 
+function cancelEndLine() {
+  if (lineStartPoint.value) {
+    lineEndPoint.value = null;
+  }
+}
+
 function updatePos({ id, pos }) {
   const { result } = findFromArray(children.value, (i) => i.id === id);
   result.pos = pos;
@@ -115,7 +142,31 @@ function handleMouseMove(e) {
 }
 
 function handleMouseUp() {
-  draggingId.value = 0;
+  if (isDragging.value === false) {
+    draggingId.value = 0;
+  }
+  isDragging.value = false;
+  if (lineStartPoint.value && lineEndPoint.value) {
+    const startId = lineStartPoint.value.targetId;
+    const { result } = findFromArray(children.value, (i) => i.id === startId);
+    const exist = result.lines.find(
+      (line) =>
+        line.start.pos === lineStartPoint.value.pos &&
+        line.end.targetId === lineEndPoint.value.targetId &&
+        line.end.pos === lineEndPoint.value.pos
+    );
+    if (!exist) {
+      result.lines.push({
+        start: {
+          pos: lineStartPoint.value.pos,
+        },
+        end: {
+          targetId: lineEndPoint.value.targetId,
+          pos: lineEndPoint.value.pos,
+        },
+      });
+    }
+  }
   lineStartPoint.value = null;
   lineEndPoint.value = null;
 }
@@ -155,5 +206,11 @@ onBeforeUnmount(() => {
   svg {
     display: block;
   }
+
+  .dash-line {
+    stroke: #000;
+    stroke-dasharray: 3 4;
+    stroke-width: 2;
+  }
 }
 </style>

+ 30 - 0
src/views/svg/utils/index.js

@@ -16,3 +16,33 @@ export function findFromArray(array, filter) {
     result: array[index],
   };
 }
+
+/**
+ * @param {'left'|'top'|'right'|'bottom'} pos
+ * @param {{x:number, y:number}} boxPos
+ * @param {{width:number, width:number}} boxSize
+ */
+export function countPointByPos(pos, boxPos, boxSize) {
+  switch (pos) {
+    case "left":
+      return {
+        cx: boxPos.x,
+        cy: boxPos.y + boxSize.height / 2,
+      };
+    case "top":
+      return {
+        cx: boxPos.x + boxSize.width / 2,
+        cy: boxPos.y,
+      };
+    case "right":
+      return {
+        cx: boxPos.x + boxSize.width,
+        cy: boxPos.y + boxSize.height / 2,
+      };
+    case "bottom":
+      return {
+        cx: boxPos.x + boxSize.width / 2,
+        cy: boxPos.y + boxSize.height,
+      };
+  }
+}