Explorar el Código

feat: 添加搜索图例 dxf双线功能

bill hace 12 horas
padre
commit
a6f1101db8

+ 1 - 0
src/core/components/line/renderer/wall/index.vue

@@ -2,6 +2,7 @@
   <v-line
     v-for="polygon in polygons"
     :config="{
+      name: props.line.id + '-view',
       opacity: opacity,
       points: flatPositions(polygon),
       fill: stroke,

+ 5 - 5
src/core/helper/split-line.vue

@@ -171,7 +171,7 @@ const rectAxisSteps = computed(() => {
 const { transform } = useProportion();
 const getWidthText = (val: number) => Math.round(transform(val)).toString();
 
-const fscale = useFixedScale();
+const inv = useViewerInvertTransformConfig();
 const axissInfo = computed(() => {
   if (!rang.value) return;
   const infos: Record<string, { points: number[]; texts: TextConfig[] }> = {
@@ -205,7 +205,7 @@ const axissInfo = computed(() => {
 
       infos.left.texts.push({
         width: width,
-        text: getWidthText(width * fscale.value),
+        text: getWidthText(width * inv.value.scaleX),
         ...tf.decompose(),
       });
     }
@@ -235,7 +235,7 @@ const axissInfo = computed(() => {
 
       infos.right.texts.push({
         width: width,
-        text: getWidthText(width * fscale.value).toString(),
+        text: getWidthText(width * inv.value.scaleX).toString(),
         ...tf.decompose(),
       });
     }
@@ -258,7 +258,7 @@ const axissInfo = computed(() => {
       const width = cur - prev;
       infos.top.texts.push({
         width: width,
-        text: getWidthText(width * fscale.value).toString(),
+        text: getWidthText(width * inv.value.scaleX).toString(),
         ...lt,
       });
     }
@@ -281,7 +281,7 @@ const axissInfo = computed(() => {
       const width = cur - prev;
       infos.bottom.texts.push({
         width: width,
-        text: getWidthText(width * fscale.value).toString(),
+        text: getWidthText(width * inv.value.scaleX).toString(),
         ...lt,
       });
     }

+ 110 - 64
src/core/hook/use-dxf.ts

@@ -15,14 +15,21 @@ import Zip from "jszip";
 import { LineData } from "../components/line";
 import { CircleData } from "../components/circle";
 import { Transform } from "konva/lib/Util";
-import { lineLen, lineVector, Pos, Size, verticalVectorLine, zeroEq } from "@/utils/math";
+import {
+  lineLen,
+  lineVector,
+  Pos,
+  Size,
+  verticalVectorLine,
+  zeroEq,
+} from "@/utils/math";
 import { RectangleData } from "../components/rectangle";
 import { useStage } from "./use-global-vars";
 import { Group } from "konva/lib/Group";
 import { Text } from "konva/lib/shapes/Text";
 import { TextData } from "../components/text";
 import { ImageData } from "../components/image";
-import { onlyId } from "@/utils/shared";
+import { asyncTimeout, onlyId } from "@/utils/shared";
 import { ArrowData, PointerPosition } from "../components/arrow";
 import { IconData } from "../components/icon";
 import {
@@ -34,6 +41,7 @@ import { nextTick } from "vue";
 import { SLineData } from "../components/sequent-line";
 import { IRect } from "konva/lib/types";
 import { LineIconData } from "../components/line-icon";
+import { Line } from "konva/lib/shapes/Line";
 
 export const useGetDXF = () => {
   const store = useStore();
@@ -161,26 +169,45 @@ export const useGetDXF = () => {
       });
     };
 
-    const writeImage = async (imgGroup: Group, scaleCallback?: (scale: Size, box: IRect) => () => void) => {
+    const writeImage = async (
+      imgGroup: Group,
+      scaleCallback?: (scale: Size, box: IRect) => () => void
+    ) => {
       let curRect = imgGroup.getClientRect();
       const oldViewMat = viewer.viewMat;
       setViewport(curRect);
       await nextTick();
       const imgRect = imgGroup.getClientRect();
-      const back = scaleCallback && scaleCallback({ width: imgRect.width / curRect.width, height: imgRect.height / curRect.height }, imgRect)
-      await nextTick()
-      const img = (await imgGroup!.toImage({
-        pixelRatio: 1,
-        quality: 1,
-        mimeType: "image/png",
-      }).catch((e) => {
-        console.error(e)
-        throw e
-      })) as HTMLImageElement;
-      back && back()
-      await nextTick()
-      const start = invMat.value.point({ x: imgRect.x, y: imgRect.y + imgRect.height });
-      const end = invMat.value.point({ x: imgRect.x + imgRect.width, y: imgRect.y });
+      const back =
+        scaleCallback &&
+        scaleCallback(
+          {
+            width: imgRect.width / curRect.width,
+            height: imgRect.height / curRect.height,
+          },
+          imgRect
+        );
+      await nextTick();
+      const img = (await imgGroup!
+        .toImage({
+          pixelRatio: 1,
+          quality: 1,
+          mimeType: "image/png",
+        })
+        .catch((e) => {
+          console.error(e);
+          throw e;
+        })) as HTMLImageElement;
+      back && back();
+      await nextTick();
+      const start = invMat.value.point({
+        x: imgRect.x,
+        y: imgRect.y + imgRect.height,
+      });
+      const end = invMat.value.point({
+        x: imgRect.x + imgRect.width,
+        y: imgRect.y,
+      });
       const name = onlyId().replace(/\-/g, "");
       const path = name + ".png";
 
@@ -198,13 +225,22 @@ export const useGetDXF = () => {
         fetch(img.src)
           .then((res) => res.blob())
           .then((blob) => zip.file(path, blob, {}))
-          .catch(e => {
-            console.error(e)
+          .catch((e) => {
+            console.error(e);
           })
       );
       viewer.setViewMat(oldViewMat);
     };
 
+    const initViewOperate = async (operate: () => void) => {
+      const oldViewMat = viewer.viewMat;
+      viewer.setViewMat(new Transform());
+      await asyncTimeout(50);
+      operate();
+      viewer.setViewMat(oldViewMat);
+      await asyncTimeout(50);
+    };
+
     for (const _item of store.sortItems) {
       if (_item.hide) continue;
 
@@ -223,34 +259,52 @@ export const useGetDXF = () => {
             }
           );
           break;
+        case "lineChunk":
         case "line":
           const litem = _item as LineData;
-          litem.lines.forEach((line) => {
-            const a = litem.points.find((p) => p.id === line.a)!;
-            const b = litem.points.find((p) => p.id === line.b)!;
-            // writer.addLine(
-            //   point3d(a.x, a.y, 0),
-            //   point3d(b.x, b.y, 0),
-            //   {
-            //     trueColor: TrueColor.fromHex(line.stroke || "#FFFFFF").toString(),
-            //   }
-            // )
 
-            writer.addLWPolyline(
-              [
-                { point: point3d(a.x, -a.y, 0) },
-                { point: point3d(b.x, -b.y, 0) },
-              ],
-              {
-                flags: LWPolylineFlags.None,
-                constantWidth: line.strokeWidth,
-                trueColor: TrueColor.fromHex(
-                  line.stroke || "#FFFFFF"
-                ).toString(),
+          await initViewOperate(() => {
+            litem.lines.forEach((line) => {
+              const $lines = stage
+                .value!.getNode()
+                .find<Line>(`.${line.id}-view`)!;
+              for (let i = 0; i < $lines.length; i++) {
+                const flatPoints = $lines[i].points();
+                const points: Pos[] = [];
+                for (let i = 0; i < flatPoints.length; i += 2) {
+                  points.push({ x: flatPoints[i], y: flatPoints[i + 1] });
+                }
+                const data: PL = {
+                  id: litem.id,
+                  points,
+                  // stroke: '#000000',
+                  // fill: line.stroke,
+                  stroke: line.stroke,
+                  strokeWidth: 1,
+                };
+                writerPolyline(data);
               }
-            );
+            });
           });
 
+          // litem.lines.forEach((line) => {
+          //   const a = litem.points.find((p) => p.id === line.a)!;
+          //   const b = litem.points.find((p) => p.id === line.b)!;
+          //   writer.addLWPolyline(
+          //     [
+          //       { point: point3d(a.x, -a.y, 0) },
+          //       { point: point3d(b.x, -b.y, 0) },
+          //     ],
+          //     {
+          //       flags: LWPolylineFlags.None,
+          //       constantWidth: line.strokeWidth,
+          //       trueColor: TrueColor.fromHex(
+          //         line.stroke || "#FFFFFF"
+          //       ).toString(),
+          //     }
+          //   );
+          // });
+
           break;
 
         case "triangle":
@@ -284,12 +338,12 @@ export const useGetDXF = () => {
           if (zeroEq(lineLen(item.points[0], item.points[1]))) {
             item = {
               ...item,
-              points: [...item.points]
-            }
+              points: [...item.points],
+            };
             item.points[0] = {
               ...item.points[0],
-              x: item.points[1].x - (item.pointerLength || 1)
-            }
+              x: item.points[1].x - (item.pointerLength || 1),
+            };
           }
           const isEnd = [PointerPosition.end, PointerPosition.all].includes(
             item.pointerPosition || PointerPosition.start
@@ -309,15 +363,11 @@ export const useGetDXF = () => {
                 .multiplyScalar(item.pointerLength! * 2)
                 .add(line[0]);
               nline[0] = start;
-              const l1 = verticalVectorLine(
-                vector,
-                start,
-                item.pointerLength! 
-              );
+              const l1 = verticalVectorLine(vector, start, item.pointerLength!);
               const l2 = verticalVectorLine(
                 vector,
                 start,
-                -item.pointerLength! 
+                -item.pointerLength!
               );
               writerPolyline({
                 points: [line[0], l1[1], l2[1]],
@@ -331,15 +381,11 @@ export const useGetDXF = () => {
                 .multiplyScalar(-item.pointerLength! * 2)
                 .add(line[1]);
               nline[1] = start;
-              const l1 = verticalVectorLine(
-                vector,
-                start,
-                item.pointerLength! 
-              );
+              const l1 = verticalVectorLine(vector, start, item.pointerLength!);
               const l2 = verticalVectorLine(
                 vector,
                 start,
-                -item.pointerLength! 
+                -item.pointerLength!
               );
               writerPolyline({
                 points: [line[1], l1[1], l2[1]],
@@ -370,23 +416,23 @@ export const useGetDXF = () => {
             .findOne<Group>(".rep-position")!;
 
           await writeImage(pathGroup, () => {
-            iconItem.strokeScaleEnabled = true
+            iconItem.strokeScaleEnabled = true;
             return () => {
-              iconItem.strokeScaleEnabled = false
-            }
+              iconItem.strokeScaleEnabled = false;
+            };
           });
           break;
-        case 'lineIcon':
+        case "lineIcon":
           const lineIconItem = _item as LineIconData;
           const linePathGroup = $stage
             .findOne<Group>(`#${lineIconItem.id}`)!
             .findOne<Group>(".rep-position")!;
 
           await writeImage(linePathGroup, () => {
-            lineIconItem.strokeScaleEnabled = true
+            lineIconItem.strokeScaleEnabled = true;
             return () => {
-              lineIconItem.strokeScaleEnabled = false
-            }
+              lineIconItem.strokeScaleEnabled = false;
+            };
           });
           break;
       }

+ 43 - 24
src/example/components/slide/slide-icons.vue

@@ -1,35 +1,42 @@
 <template>
-  <ElCollapse class="icon-layout" v-model="activeGroups">
-    <ElCollapseItem
-      v-for="group in searchGroups"
-      :name="group.name"
-      v-if="searchGroups.length"
-    >
-      <template #title>
-        <h2>{{ group.name }}</h2>
+  <div class="icon-layout">
+    <ElInput v-model="keyword" placeholder="搜索图例" class="search" style="height: 34px">
+      <template #prefix>
+        <icon name="Search" size="16px" />
       </template>
+    </ElInput>
+    <ElCollapse class="icon-menu" v-model="activeGroups">
+      <ElCollapseItem
+        v-for="group in searchGroups"
+        :name="group.name"
+        v-if="searchGroups.length"
+      >
+        <template #title>
+          <h2>{{ group.name }}</h2>
+        </template>
 
-      <div class="type-children" v-for="typeChildren in group.children">
-        <h3 v-if="typeChildren.name">{{ typeChildren.name }}</h3>
-        <div class="icon-items">
-          <div
-            v-for="item in typeChildren.children"
-            @click="drawIcon(item)"
-            :class="{ active: activeName === item.name }"
-          >
-            <Icon :name="item.icon" size="32px" :color="item.color" />
-            <span>{{ item.name }}</span>
+        <div class="type-children" v-for="typeChildren in group.children">
+          <h3 v-if="typeChildren.name">{{ typeChildren.name }}</h3>
+          <div class="icon-items">
+            <div
+              v-for="item in typeChildren.children"
+              @click="drawIcon(item)"
+              :class="{ active: activeName === item.name }"
+            >
+              <Icon :name="item.icon" size="32px" :color="item.color" />
+              <span>{{ item.name }}</span>
+            </div>
           </div>
         </div>
-      </div>
-    </ElCollapseItem>
-    <el-empty description="暂无数据" v-else />
-  </ElCollapse>
+      </ElCollapseItem>
+      <el-empty description="暂无匹配结果" v-else />
+    </ElCollapse>
+  </div>
 </template>
 
 <script lang="ts" setup>
 import { computed, ref } from "vue";
-import { ElCollapse, ElCollapseItem, ElEmpty } from "element-plus";
+import { ElCollapse, ElCollapseItem, ElEmpty, ElInput } from "element-plus";
 import { defaultStyle, getIconStyle } from "@/core/components/icon/index.ts";
 import { Draw } from "../container/use-draw";
 import { IconGroup, IconItem } from "@/example/constant";
@@ -106,16 +113,26 @@ props.cref &&
   background-color: var(--el-menu-bg-color);
   border-right: solid 1px var(--el-menu-border-color);
   overflow-y: auto;
-  padding: 0 20px;
+  padding: 20px;
   font-size: 14px;
   color: #333;
 
+  .search {
+    margin-bottom: 15px;
+  }
+
+  .icon-menu {
+    border: none;
+  }
+
   h2 {
     font-size: 16px;
   }
+
   h3 {
     font-size: 14px;
   }
+
   h2,
   h3 {
     color: inherit;
@@ -133,6 +150,7 @@ props.cref &&
 .type-children {
   margin-left: 10px;
 }
+
 .icon-items {
   margin-left: -10px;
   display: flex;
@@ -156,6 +174,7 @@ props.cref &&
     &.active {
       background: var(--el-color-primary-light-7);
     }
+
     span {
       margin-top: 10px;
     }

+ 1 - 1
src/example/constant.ts

@@ -77,7 +77,7 @@ const traceIcons = [
 ];
 export const iconGroups: IconGroup[] = [
   {
-    name: "常用名称",
+    name: "户型",
     children: [
       {
         name: "门",