Просмотр исходного кода

feat: 添加线段拖拽的吸附功能

bill 2 месяцев назад
Родитель
Сommit
521745778b

+ 14 - 6
src/core/components/line/temp-line.vue

@@ -41,6 +41,9 @@ import { Group } from "konva/lib/Group";
 import { useOperMode } from "@/core/hook/use-status.ts";
 import { useMouseShapeStatus } from "@/core/hook/use-mouse-status.ts";
 import { Pos } from "@/utils/math.ts";
+import { useCustomSnapInfos, useSnap, useSnapConfig, useSnapResultInfo } from "@/core/hook/use-snap.ts";
+import { ComponentSnapInfo } from "../index.ts";
+import { generateSnapInfos } from "../util.ts";
 
 const props = defineProps<{
   data: LineData;
@@ -63,7 +66,6 @@ const dragPointIds = ref<string[]>();
 let track = false;
 let ctx: NLineDataCtx;
 const updateBeforeHandler = (ids: string[]) => {
-  console.log("before");
   dragPointIds.value = ids;
   track = true;
   ctx = getInitCtx();
@@ -105,14 +107,20 @@ const updateHandler = () => {
   dragPointIds.value = undefined;
 };
 
-let moveHandler: ReturnType<typeof genMoveLineHandler>;
+const resultInfo = useSnapResultInfo();
+const snapConfig = useSnapConfig()
+let handler: ReturnType<typeof genMoveLineHandler>;
 const dragstartLineHandler = (line: LineData["lines"][0]) => {
-  moveHandler = genMoveLineHandler(props.data, line.id);
+  updateBeforeHandler([line.a, line.b]);
+  handler = genMoveLineHandler(props.data, line.id, snapConfig, resultInfo, ctx);
 };
-const dragLineHandler = (line: LineData["lines"][0], ps: Pos[]) => {
-  moveHandler(ps);
+const dragLineHandler = (_: any, ps: Pos[]) => {
+  handler.move(ps);
+};
+const dragendLineHandler = () => {
+  handler.end();
+  updateHandler();
 };
-const dragendLineHandler = (line: LineData["lines"][0]) => {};
 
 const shape = ref<DC<Group>>();
 useZIndex(shape, data);

+ 120 - 32
src/core/components/line/use-draw.ts

@@ -19,16 +19,20 @@ import {
   getVectorLine,
   lineIntersection,
   lineLen,
+  linePointLen,
   linePointProjection,
   lineVector,
   Pos,
-  vector,
   vector2IncludedAngle,
   verticalVector,
   zeroEq,
 } from "@/utils/math";
 import { defaultStyle, getSnapInfos, type LineData } from "./";
-import { useCustomSnapInfos } from "@/core/hook/use-snap";
+import {
+  SnapResultInfo,
+  useCustomSnapInfos,
+  useSnapConfig,
+} from "@/core/hook/use-snap";
 import { MathUtils, Vector2 } from "three";
 import { getBaseItem } from "../util";
 
@@ -434,12 +438,14 @@ export const normalLineData = (data: LineData, ctx: NLineDataCtx) => {
 export const genMoveLineHandler = (
   data: LineData,
   lineId: string,
+  snapConfig: ReturnType<typeof useSnapConfig>,
+  snapResult: SnapResultInfo,
   ctx = getInitCtx()
 ) => {
   const line = data.lines.find((line) => line.id === lineId)!;
   const pointIds = [line.a, line.b];
   const points = pointIds.map((id) => data.points.find((p) => p.id === id)!);
-  const lineDire = lineVector(points)
+  const lineDire = lineVector(points);
   const initPoints = copy(points);
   const angleRange = [MathUtils.degToRad(10), MathUtils.degToRad(170)];
   const getJoinLine = (pId: string) =>
@@ -462,6 +468,7 @@ export const genMoveLineHandler = (
     const joinLineDires: Vector2[] = [];
     const line = [points[ndx], points[Number(!ndx)]];
     const lineDire = lineVector(line);
+    const joinPoints: LineData["points"] = [];
 
     let invAngle = Number.MAX_VALUE;
     let invSelectLineId: string;
@@ -472,6 +479,7 @@ export const genMoveLineHandler = (
     let alongSelectLineDire: Vector2 | null = null;
 
     for (const line of joinLines) {
+      joinPoints.push(...line.points.filter((p) => !points.includes(p)));
       const joinDire = lineVector(line.points);
       joinLineDires.push(joinDire);
 
@@ -530,16 +538,19 @@ export const genMoveLineHandler = (
             rangMod(vector2IncludedAngle(dire, info.selectLineDire), Math.PI)
           )
       );
-    return { ...info, needSplit, needVertical };
+    return { ...info, needSplit, needVertical, joinPoints };
   };
 
   let refInfos: ReturnType<typeof getRefInfo>[];
   let snapLines: (null | Pos[])[];
   let inited = false;
+  let norNdx = -1;
 
   const init = (moveDires: Vector2[]) => {
     refInfos = [getRefInfo(moveDires[0], 0), getRefInfo(moveDires[0], 1)];
     snapLines = [];
+    let minAngle = Math.PI / 2;
+    const vLineDire = verticalVector(lineDire);
     for (let i = 0; i < refInfos.length; i++) {
       const refInfo = refInfos[i];
       if (!refInfo) {
@@ -570,16 +581,38 @@ export const genMoveLineHandler = (
       const dire = refInfo.needVertical
         ? verticalVector(refInfo.selectLineDire)
         : refInfo.selectLineDire;
+
+      const angle = rangMod(vector2IncludedAngle(dire, vLineDire), Math.PI / 2);
+      if (angle < minAngle) {
+        norNdx = i;
+        minAngle = angle;
+      }
       snapLines[i] = getVectorLine(dire, copy(points[i]), 10);
     }
   };
-  const assignPos = (origin: LineData['points'][0], target: Pos) => {
-    origin.x = target.x
-    origin.y = target.y
-    ctx.update.points[origin.id] = origin
-  }
+  const assignPos = (origin: LineData["points"][0], target: Pos) => {
+    origin.x = target.x;
+    origin.y = target.y;
+    ctx.update.points[origin.id] = origin;
+  };
 
-  const handler = (finalPoss: Pos[]) => {
+  const updateOtPoint = (ndx: number) => {
+    const uNdx = ndx === 1 ? 0 : 1;
+    const move = new Vector2(
+      points[ndx].x - initPoints[ndx].x,
+      points[ndx].y - initPoints[ndx].y
+    );
+    if (!snapLines[uNdx]) {
+      assignPos(points[uNdx], move.add(initPoints[uNdx]));
+    } else {
+      assignPos(
+        points[uNdx],
+        lineIntersection(getVectorLine(lineDire, points[ndx]), snapLines[uNdx])!
+      );
+    }
+  };
+
+  const move = (finalPoss: Pos[]) => {
     if (!inited) {
       const moveDires = finalPoss.map((pos, ndx) =>
         lineVector([initPoints[ndx], pos])
@@ -589,33 +622,88 @@ export const genMoveLineHandler = (
     }
 
     if (!snapLines[0] && !snapLines[1]) {
-      assignPos(points[0], finalPoss[0])
-      assignPos(points[1], finalPoss[1])
-      return;
+      assignPos(points[0], finalPoss[0]);
+      assignPos(points[1], finalPoss[1]);
     } else if (!snapLines[0]) {
-      const pos = linePointProjection(snapLines[1]!, finalPoss[1])
-      assignPos(points[1], pos)
-      assignPos(points[0], pos.sub(initPoints[1]).add(initPoints[0]))
-      return;
+      const pos = linePointProjection(snapLines[1]!, finalPoss[1]);
+      assignPos(points[1], pos);
+      updateOtPoint(1);
     } else if (!snapLines[1]) {
-      const pos = linePointProjection(snapLines[0]!, finalPoss[0])
-      assignPos(points[0], pos)
-      assignPos(points[1], pos.sub(initPoints[0]).add(initPoints[1]))
-      return;
+      const pos = linePointProjection(snapLines[0]!, finalPoss[0]);
+      assignPos(points[0], pos);
+      updateOtPoint(0);
+    } else {
+      const pos = linePointProjection(snapLines[norNdx]!, finalPoss[norNdx]);
+      assignPos(points[norNdx], pos);
+      updateOtPoint(norNdx);
     }
+  };
 
-    const moves = snapLines.map((snapLine, i) => {
-      const pos = !snapLine ? finalPoss[i] : linePointProjection(snapLine, finalPoss[i])
-      return vector(pos).sub(initPoints[i])
-    });
-    if (moves[0].lengthSq() > moves[1].lengthSq()) {
-      assignPos(points[0], moves[0].add(initPoints[0]));
-      assignPos(points[1], lineIntersection(getVectorLine(lineDire, points[0]), snapLines[1])!)
-    } else {
-      assignPos(points[1], moves[1].add(initPoints[1]));
-      assignPos(points[0], lineIntersection(getVectorLine(lineDire, points[1]), snapLines[0])!)
+  const getSnapRefPoint = (point: Pos, refPoints: Pos[], line: Pos[] | null) => {
+    for (const refPoint of refPoints) {
+      if (
+        lineLen(refPoint, point) < snapConfig.snapOffset &&
+        (!line || zeroEq(linePointLen(line, refPoint)))
+      ) {
+        return refPoint;
+      }
+    }
+  };
+
+  const snap = () => {
+    snapResult.clear();
+    let refPoint: Pos | undefined = undefined;
+    let ndx = -1;
+
+    const useRefPoint = () => {
+      const hv = [
+        { join: refPoint, refDirection: { x: 0, y: 1 } },
+        { join: refPoint, refDirection: { x: 1, y: 0 } },
+      ];
+      snapResult.attractSnaps.push(...(hv as any));
+      assignPos(points[ndx], refPoint!);
+      updateOtPoint(ndx);
+    };
+
+    if (refInfos[0]?.joinPoints) {
+      refPoint = getSnapRefPoint(points[0], refInfos[0]?.joinPoints, snapLines[0]);
+      if (refPoint) {
+        ndx = 0;
+        return useRefPoint();
+      }
+    }
+    if (refInfos[1]?.joinPoints) {
+      refPoint = getSnapRefPoint(points[1], refInfos[1]?.joinPoints, snapLines[1]);
+      if (refPoint) {
+        ndx = 1;
+        return useRefPoint();
+      }
+    }
+
+    const usedPoints = [
+      ...(refInfos[0]?.joinPoints || []),
+      ...(refInfos[1]?.joinPoints || []),
+      ...points,
+    ];
+    const refPoints = data.points.filter((p) => !usedPoints.includes(p));
+    for (let i = 0; i < points.length; i++) {
+      refPoint = getSnapRefPoint(points[i], refPoints, snapLines[i]);
+      if (refPoint) {
+        ndx = i;
+        return useRefPoint();
+      }
     }
   };
 
-  return handler;
+  const end = () => {
+    snapResult.clear();
+  };
+
+  return {
+    move: (ps: Pos[]) => {
+      move(ps);
+      snap();
+    },
+    end,
+  };
 };

+ 0 - 1
src/example/platform/platform-draw.ts

@@ -180,7 +180,6 @@ const drawLayerResource = async (
     lines: [],
     points: [],
     polygon: [],
-    attitude: [1, 0, 0, 1, 0, 0],
     createTime: createTime,
   };