Procházet zdrojové kódy

feat: 优化键盘快捷操作

bill před 1 měsícem
rodič
revize
4771969fea

+ 19 - 4
src/core/components/line-icon/icon.vue

@@ -65,6 +65,7 @@ const { shape, tData, data, operateMenus, describes } = useComponentStatus({
   selfData: true,
   customTransform(callback, shape, data) {
     let prevInvMat: Transform;
+    let posOffset: Pos | null = null;
     return useCustomTransformer(shape, data, {
       getRepShape() {
         const group = new Group();
@@ -85,10 +86,21 @@ const { shape, tData, data, operateMenus, describes } = useComponentStatus({
       },
       handler(data, mat) {
         if (pos.value && !getOperType()) {
-          const rpos = viewMat.value.point(pos.value);
+          if (!posOffset) {
+            const real = viewMat.value.point(pos.value);
+            const prevDec = prevInvMat.decompose();
+            posOffset = {
+              x: real.x - prevDec.x,
+              y: real.y - prevDec.y,
+            };
+          }
+          const rpos = viewMat.value.point({
+            x: pos.value.x,
+            y: pos.value.y,
+          });
           const m = mat.m;
-          m[4] = rpos.x;
-          m[5] = rpos.y;
+          m[4] = rpos.x - posOffset.x;
+          m[5] = rpos.y - posOffset.y;
           mat = new Transform(m);
         }
         matResponse({
@@ -100,7 +112,10 @@ const { shape, tData, data, operateMenus, describes } = useComponentStatus({
 
         return true;
       },
-      callback,
+      callback() {
+        posOffset = null;
+        callback();
+      },
       openSnap: false,
       transformerConfig: {
         flipEnabled: true,

+ 1 - 1
src/core/hook/use-global-vars.ts

@@ -297,7 +297,7 @@ export const useDownKeys = installGlobalVar(() => {
       evHandler(ev, keyKeys);
     }),
     listener(window, "mousemove", (ev) => {
-      evHandler(ev, mouseKeys);
+      evHandler(ev, keyKeys);
     })
   );
   const keys = reactive(new Set<string>());

+ 0 - 1
src/example/env.ts

@@ -1,4 +1,3 @@
-import { inRevise } from "@/utils/shared";
 import { computed, ref, watch } from "vue";
 
 export const urlUpdateQuery = (

+ 24 - 0
src/example/fuse/enter.ts

@@ -281,6 +281,29 @@ const uploadResourse = genLoading(async (file: File) => {
   }
 });
 
+const getTableTemp = () => {
+  let table: Record<string, string>
+  let title: string = params.value.title
+  if (params.value.table) {
+    try {
+      table = JSON.parse(params.value.table)
+    } catch (e) {
+      console.log('tableTemp模板解析失败')
+    }
+  }
+  if (!table!) {
+    table = {
+      案发时间: '',
+      案发地点: '',
+      绘图单位: '',
+      绘图人: '',
+      绘图时间: '',
+    }
+    title = '默认标题'
+  }
+  return { table, title }
+}
+
 window.platform = {
   resourceURLS,
   viewURLS,
@@ -291,6 +314,7 @@ window.platform = {
   saveTabulationData,
   uploadResourse,
   getTabulationId,
+  getTableTemp
 };
 
 /* @vite-ignore */

+ 86 - 64
src/example/fuse/views/tabulation/gen-tab.ts

@@ -41,19 +41,28 @@ export const transformPaper = (
 
 export const getCoverPaperScale = (cover: ImageData, paperKey: PaperKey) => {
   let pixelScale = (cover.widthRaw! / cover.width) * cover.proportion!.scale;
-  console.log(cover.width, cover.height)
+  console.log(cover.width, cover.height);
   const realPixelScale = paperConfigs[paperKey].scale;
   return realPixelScale * pixelScale;
 };
 
-export const setCoverPaperScale = (cover: ImageData, paperKey: PaperKey, scale: number) => {
+export const setCoverPaperScale = (
+  cover: ImageData,
+  paperKey: PaperKey,
+  scale: number
+) => {
   const realPixelScale = paperConfigs[paperKey].scale;
-  cover.width = cover.widthRaw! / ((scale / realPixelScale) /cover.proportion!.scale)
-  cover.height = (cover.heightRaw! / cover.widthRaw!) * cover.width
-  console.log(cover.width, cover.height)
-}
+  cover.width =
+    cover.widthRaw! / (scale / realPixelScale / cover.proportion!.scale);
+  cover.height = (cover.heightRaw! / cover.widthRaw!) * cover.width;
+  console.log(cover.width, cover.height);
+};
 
-export const genTabulationData = async (paperKey: PaperKey, compass?: number, cover?: TabCover | null) => {
+export const genTabulationData = async (
+  paperKey: PaperKey,
+  compass?: number,
+  cover?: TabCover | null
+) => {
   const { margin, size } = getPaperConfig(
     paperConfigs[paperKey].size,
     paperConfigs[paperKey].scale
@@ -74,22 +83,21 @@ export const genTabulationData = async (paperKey: PaperKey, compass?: number, co
       fontColor: "#000000",
     };
     const valueColl = { ...nameColl, width: w2 };
+    const tableTemp: Record<string, string> =
+      window.platform.getTableTemp().table;
 
     const data = {
       ...getBaseItem(),
-      content: [
-        [{ ...nameColl, content: "案发时间" }, valueColl],
-        [{ ...nameColl, content: "案发地点" }, valueColl],
-        [{ ...nameColl, content: "绘图单位" }, valueColl],
-        [{ ...nameColl, content: "绘图人" }, valueColl],
-        [{ ...nameColl, content: "绘图时间" }, valueColl],
-      ],
+      content: Object.entries(tableTemp).map(([name, value]) => [
+        { ...nameColl, content: name },
+        { ...valueColl, content: value },
+      ]),
       fontSize: getRealPixel(4, paperKey),
       key: tableTableKey,
       width: nameColl.width + valueColl.width,
       height: nameColl.height * 5,
       mat: [1, 0, 0, 1, 0, 0],
-      fill: null
+      fill: null,
     };
 
     const pos = getFixPosition(
@@ -111,7 +119,7 @@ export const genTabulationData = async (paperKey: PaperKey, compass?: number, co
     const tableCoverScale = tableCoverWidth / tableCoverHeight;
 
     let width: number, height: number;
-    
+
     if (rectScale > tableCoverScale) {
       width = transformPaper(tableCoverWidth, paperKey, "a4");
       height = width / rectScale;
@@ -136,7 +144,7 @@ export const genTabulationData = async (paperKey: PaperKey, compass?: number, co
       width,
       height,
       mat: [1, 0, 0, 1, 0, 0],
-      itemName: '比例'
+      itemName: "比例",
     };
     const pos = getFixPosition(
       {
@@ -150,13 +158,13 @@ export const genTabulationData = async (paperKey: PaperKey, compass?: number, co
     coverData.mat[5] = pos.y;
 
     const scale = getCoverPaperScale(coverData, paperKey);
-    setCoverPaperScale(coverData, paperKey, Math.round(scale / 10) * 10 || 10)
+    setCoverPaperScale(coverData, paperKey, Math.round(scale / 10) * 10 || 10);
     return coverData;
   };
 
   const getCoverScale = (cover: ImageData) => {
     const scale = (cover.widthRaw! / cover.width) * cover.proportion!.scale;
-    console.log(cover)
+    console.log(cover);
     const text = {
       ...getBaseItem(),
       content: `1:${scale}`,
@@ -179,7 +187,7 @@ export const genTabulationData = async (paperKey: PaperKey, compass?: number, co
   const getTitle = () => {
     const title = {
       ...getBaseItem(),
-      content: "默认标题",
+      content: window.platform.getTableTemp().title,
       width: getRealPixel(90, paperKey),
       heihgt: getRealPixel(14.4, paperKey),
       fontSize: getRealPixel(12, paperKey),
@@ -197,25 +205,29 @@ export const genTabulationData = async (paperKey: PaperKey, compass?: number, co
   };
 
   const getCompass = async () => {
-    const mat = new Transform().rotate(MathUtils.degToRad(compass!))
-    const style =await getIconStyle('./icons/compass.svg', getRealPixel(37.3366 / 2.3, paperKey), getRealPixel(60 / 2.3, paperKey))
-    
+    const mat = new Transform().rotate(MathUtils.degToRad(compass!));
+    const style = await getIconStyle(
+      "./icons/compass.svg",
+      getRealPixel(37.3366 / 2.3, paperKey),
+      getRealPixel(60 / 2.3, paperKey)
+    );
+
     const data: IconData = {
       ...getBaseItem(),
       ...style,
       disableDelete: true,
-      itemName: '指南针',
+      itemName: "指南针",
       coverOpcatiy: 0,
       strokeScaleEnabled: false,
       key: tableCompassKey,
       mat: mat.m,
-      name: '指南针'
+      name: "指南针",
     };
-    console.error('指南针', data)
-    
+    console.error("指南针", data);
+
     const pos = getFixPosition(
       {
-        right: getRealPixel(8, paperKey) + margin[1] ,
+        right: getRealPixel(8, paperKey) + margin[1],
         top: getRealPixel(42, paperKey) + margin[2],
       },
       data,
@@ -224,26 +236,31 @@ export const genTabulationData = async (paperKey: PaperKey, compass?: number, co
     data.mat[4] = pos.x;
     data.mat[5] = pos.y;
     return data;
-  }
+  };
 
   const data: DrawData = {
     table: [getTable()],
     text: [getTitle()],
-  }
-  const image = await getCover()
+  };
+  const image = await getCover();
   if (image) {
-    data.image = [image]
-    data.text!.push(getCoverScale(image))
+    data.image = [image];
+    data.text!.push(getCoverScale(image));
   }
   if (compass !== undefined) {
-    data.icon = [await getCompass()]
+    data.icon = [await getCompass()];
   }
 
-  return data
+  return data;
 };
 
-export const repTabulationStore = async (paperKey: PaperKey, compass?: number, cover?: TabCover, store?: StoreData) => {
-  const repData = await genTabulationData(paperKey, compass, cover)
+export const repTabulationStore = async (
+  paperKey: PaperKey,
+  compass?: number,
+  cover?: TabCover,
+  store?: StoreData
+) => {
+  const repData = await genTabulationData(paperKey, compass, cover);
   const layer = store?.layers && store?.layers[defaultLayer];
 
   if (!layer) {
@@ -255,51 +272,56 @@ export const repTabulationStore = async (paperKey: PaperKey, compass?: number, c
       },
       layers: {
         ...(store?.layers || {}),
-        [defaultLayer]: repData
-      }
-    }
+        [defaultLayer]: repData,
+      },
+    };
   }
 
   if (repData.image?.length) {
-    const imageData = repData.image[0]
-    const images = layer.image || []
-    const imageNdx = images.findIndex(item => item.key === imageData.key)
-    
+    const imageData = repData.image[0];
+    const images = layer.image || [];
+    const imageNdx = images.findIndex((item) => item.key === imageData.key);
+
     if (~imageNdx) {
-      images[imageNdx] = imageData
+      images[imageNdx] = imageData;
       images[imageNdx] = {
         ...imageData,
-        mat: images[imageNdx].mat
-      }
+        mat: images[imageNdx].mat,
+      };
     } else {
-      images.push(imageData)
+      images.push(imageData);
     }
-    layer.image = images
-
+    layer.image = images;
 
-    const scaleData = repData.text!.find(item => item.key === tableCoverScaleKey)!
-    const texts = layer.text || []
-    const textNdx = texts.findIndex(item => item.key === scaleData.key)
+    const scaleData = repData.text!.find(
+      (item) => item.key === tableCoverScaleKey
+    )!;
+    const texts = layer.text || [];
+    const textNdx = texts.findIndex((item) => item.key === scaleData.key);
     if (~textNdx) {
-      texts[textNdx].content = scaleData.content
+      texts[textNdx].content = scaleData.content;
     } else {
-      texts.push(scaleData)
+      texts.push(scaleData);
     }
-    layer.text = texts
+    layer.text = texts;
   }
   if (repData.icon) {
-    const iconData = repData.icon[0]
-    const icons = layer.icon || []
-    const iconNdx = icons.findIndex(item => item.key === iconData.key)
+    const iconData = repData.icon[0];
+    const icons = layer.icon || [];
+    const iconNdx = icons.findIndex((item) => item.key === iconData.key);
     if (~iconNdx) {
-      icons[iconNdx] = iconData
+      icons[iconNdx] = iconData;
     } else {
-      icons.push(iconData)
+      icons.push(iconData);
     }
-    layer.icon = icons
+    layer.icon = icons;
+  }
+  if (import.meta.env.DEV) {
+    layer.table = repData.table
+    layer.text = repData.text
   }
 
-  store.layers[defaultLayer] = layer
+  store.layers[defaultLayer] = layer;
 
   return store;
-}
+};

+ 2 - 0
src/utils/math-clip.ts

@@ -70,3 +70,5 @@ export function polygonDifferenceOnly(subject: Pos[], clips: Pos[][]): Pos[] {
   }
   return maxPoly;
 }
+
+

+ 80 - 19
src/utils/math.ts

@@ -452,6 +452,24 @@ export const isPolygonLineIntersect = (polygon: Pos[], line: Pos[]) => {
   return false;
 };
 
+
+/**
+ * 线段与多边形交点
+ * @param polygon 多边形
+ * @param line 检测线段
+ * @returns
+ */
+export const polygonLineIntersect = (polygon: Pos[], line: Pos[]) => {
+  const ps: Pos[] =[]
+  for (let i = 0; i < polygon.length; i++) {
+    const line2 = [polygon[i], polygon[(i + 1) % polygon.length]]
+    const p = lineIntersection(line2, line)
+    if (p && lineInner(line, p) && lineInner(line2, p)) {
+      ps.push(p)
+    }
+  }
+  return ps
+};
 /**
  * 判断点是否在多边形内部
  * @param polygon 多边形顶点数组,按顺时针或逆时针顺序排列
@@ -602,7 +620,6 @@ export const getLineRelationMat = (l1: [Pos, Pos], l2: [Pos, Pos]) => {
 
 // 判断两向量是否垂直
 export const isVertical = (v1: Pos, v2: Pos) => {
-  console.log(vector(v1).dot(v2));
   return zeroEq(vector(v1).dot(v2));
 };
 
@@ -682,9 +699,29 @@ export const getLEJLineAngle = (originLine: Pos[], targetLine: Pos[]) => {
     originNdx,
     targetNdx,
     targetPoints,
-    targetInvFlag
+    targetInvFlag,
   };
 };
+
+const getLinePolygonOverdo = (polygon: Pos[], slideLine: Pos[]) => {
+  const sideJoins = polygonLineIntersect(polygon, slideLine);
+
+  // 完全穿插而过
+  if (sideJoins.length > 1) {
+    return -1;
+    // 完全包含在多边形内
+  } else if (
+    sideJoins.length === 0 &&
+    slideLine.some((p) => isPolygonPointInner(polygon, p))
+  ) {
+    return -1;
+  } else if (sideJoins.length === 1) {
+    return sideJoins[0];
+  } else {
+    return 1;
+  }
+};
+
 /**
  * 获取两变短延伸后的平湖处理
  * @param origin
@@ -712,18 +749,6 @@ export const getLineEdgeJoinInfo = (
   const targetEdges = getLineEdges(targetPoints, target.width);
   const originEdges = getLineEdges(origin.points, origin.width);
 
-  const targetJoinNdxs = originNdx === 0 ? [0, 3] : [1, 2];
-  const originJoinNdxs = originNdx === 0 ? [1, 2] : [0, 3];
-  // 如果交点边缘在另一条线中则不处理
-  if (
-    originJoinNdxs.some((i) =>
-      isPolygonPointInner(targetEdges, originEdges[i])
-    ) ||
-    targetJoinNdxs.some((i) => isPolygonPointInner(originEdges, targetEdges[i]))
-  ) {
-    return;
-  }
-
   const center = lineCenter([...origin.points, ...target.points]);
 
   const originEdgesInv =
@@ -737,6 +762,40 @@ export const getLineEdgeJoinInfo = (
     originOuter = [originEdges[3], originEdges[2]];
   }
 
+  let innerJoin: Pos | null = null;
+  // 如果交点边缘在另一条线中,则交点更改为另一条线上
+  const targetJoinNdxs = originNdx === 0 ? [0, 3] : [1, 2];
+  const originJoinNdxs = originNdx === 0 ? [1, 2] : [0, 3];
+
+  // let innerJoinFlag = getLinePolygonOverdo(
+  //   originEdges,
+  //   targetJoinNdxs.map((i) => targetEdges[i])
+  // );
+  // if (innerJoinFlag === -1) {
+  //   return;
+  // } else if (innerJoinFlag !== 1) {
+  //   innerJoin = innerJoinFlag as Pos;
+  // }
+  // if (!innerJoin) {
+  //   innerJoinFlag = getLinePolygonOverdo(
+  //     targetEdges,
+  //     originJoinNdxs.map((i) => originEdges[i])
+  //   );
+  //   if (innerJoinFlag === -1) {
+  //     return;
+  //   } else if (innerJoinFlag !== 1) {
+  //     innerJoin = innerJoinFlag as Pos;
+  //   }
+  // }
+  if (
+    originJoinNdxs.some((i) =>
+      isPolygonPointInner(targetEdges, originEdges[i])
+    ) ||
+    targetJoinNdxs.some((i) => isPolygonPointInner(originEdges, targetEdges[i]))
+  ) {
+    return;
+  }
+
   const targetEdgesInv =
     lineLen(center, targetEdges[0]) > lineLen(center, targetEdges[3]);
   let targetInner, targetOuter;
@@ -748,14 +807,16 @@ export const getLineEdgeJoinInfo = (
     targetOuter = [targetEdges[3], targetEdges[2]];
   }
 
-  const outerJoin = lineIntersection(targetOuter, originOuter);
+  let outerJoin = lineIntersection(targetOuter, originOuter);
   if (!outerJoin) {
     return;
   }
 
-  const innerJoin = lineIntersection(targetInner, originInner);
   if (!innerJoin) {
-    return;
+    innerJoin = lineIntersection(targetInner, originInner);
+    if (!innerJoin) {
+      return;
+    }
   }
 
   // 如果内交点均不在两条内线上则不处理
@@ -763,7 +824,7 @@ export const getLineEdgeJoinInfo = (
     !lineInner(targetInner, innerJoin) &&
     !lineInner(originInner, innerJoin)
   ) {
-    return;
+    // return;
   }
 
   let originInnerPoints: Pos[] = [innerJoin];
@@ -805,5 +866,5 @@ export const getLineEdgeJoinInfo = (
     );
   }
 
-  return originRepInfos
+  return originRepInfos;
 };

+ 13 - 2
需求

@@ -1,3 +1,14 @@
-线段可删除
+两线段过度规则
 
-设置比例
+1.两线段夹角小于20度采用 裁剪线过渡法,用两线段的外边缘 延长产生的交点与线段共用点连接,产生一条线段,这条线段就是过度边
+2.两线段夹角大于20度采用 相交过度法, 外边缘相交  内边缘相交产生的点互相连接
+
+异常情况:
+  1.如果一条线段非公用点一侧的侧边线,与另一条侧边线产生了交点,则不过度使用原始视觉(因为交点法已经不能产品好的效果)
+  2.如果两线段不存在外交点或者内交点则不过度。(一般是平行线,)
+
+多线段过度规则:
+  1.选取两最大夹角的线段作为优先处理过度,使用两线段过度规则
+  2.排除选取过的线段,再选择两个夹角最大的线段做两线端规则(重复1,2,1,2) 直到没有线段,或者剩下一条线段
+  3.所有过度的按优先级进行放置,优先选取的在上面,次级的在下面,进行裁剪。
+