1
0

4 Коммиты aae4a2ef15 ... b3e929bc56

Автор SHA1 Сообщение Дата
  bill b3e929bc56 fix: 删除后isHover不更新问题 1 день назад
  bill cb14adc072 feat: 添加纯线类型 1 день назад
  bill 3a8ae21e92 feat: 优化矢量缩放频率 2 дней назад
  bill b05a69b66b feat: 增加矢量支持 2 дней назад
56 измененных файлов с 766 добавлено и 289 удалено
  1. 1 1
      package.json
  2. 10 21
      src/core/components/arrow/arrow.vue
  3. 2 6
      src/core/components/arrow/index.ts
  4. 28 4
      src/core/components/arrow/temp-arrow.vue
  5. 4 1
      src/core/components/circle/circle.vue
  6. 2 2
      src/core/components/circle/index.ts
  7. 12 1
      src/core/components/circle/temp-circle.vue
  8. 2 0
      src/core/components/icon/icon.ts
  9. 10 1
      src/core/components/icon/icon.vue
  10. 1 0
      src/core/components/image/index.ts
  11. 4 0
      src/core/components/index.ts
  12. 121 0
      src/core/components/line-chunk/index.ts
  13. 4 1
      src/core/components/line-icon/icon.vue
  14. 2 0
      src/core/components/line-icon/index.ts
  15. 78 51
      src/core/components/line/attach-server.ts
  16. 8 3
      src/core/components/line/index.ts
  17. 1 1
      src/core/components/line/line.vue
  18. 10 10
      src/core/components/line/renderer/wall/index.vue
  19. 25 15
      src/core/components/line/renderer/wall/view.ts
  20. 20 6
      src/core/components/line/single-line.vue
  21. 3 1
      src/core/components/line/single-point.vue
  22. 8 4
      src/core/components/line/temp-line.vue
  23. 27 10
      src/core/components/line/use-draw.ts
  24. 2 2
      src/core/components/polygon/index.ts
  25. 9 1
      src/core/components/polygon/polygon.vue
  26. 13 1
      src/core/components/polygon/temp-polygon.vue
  27. 2 3
      src/core/components/rectangle/index.ts
  28. 3 1
      src/core/components/rectangle/rectangle.vue
  29. 13 2
      src/core/components/rectangle/temp-rectangle.vue
  30. 19 6
      src/core/components/share/edit-line.vue
  31. 10 3
      src/core/components/share/edit-point.vue
  32. 4 2
      src/core/components/share/edit-polygon.vue
  33. 12 7
      src/core/components/share/size-line.vue
  34. 3 3
      src/core/components/triangle/index.ts
  35. 12 1
      src/core/components/triangle/temp-triangle.vue
  36. 4 1
      src/core/components/triangle/triangle.vue
  37. 7 5
      src/core/helper/split-line.vue
  38. 38 0
      src/core/hook/use-describe.ts
  39. 1 0
      src/core/hook/use-draw.ts
  40. 9 0
      src/core/hook/use-mouse-status.ts
  41. 5 7
      src/core/hook/use-selection.ts
  42. 0 1
      src/core/hook/use-transformer.ts
  43. 13 1
      src/core/hook/use-viewer.ts
  44. 40 0
      src/core/html-mount/propertys/describes.ts
  45. 6 6
      src/core/html-mount/propertys/index.ts
  46. 1 0
      src/core/html-mount/propertys/mount-describes.vue
  47. 0 1
      src/core/html-mount/propertys/mount.vue
  48. 0 0
      src/core/html-mount/propertys/sys-describes.json
  49. 44 44
      src/core/store/store.ts
  50. 7 5
      src/core/viewer.ts
  51. 46 4
      src/example/components/slide/actions.ts
  52. 5 1
      src/example/constant.ts
  53. 8 4
      src/example/dialog/basemap/leaflet/index.vue
  54. 37 24
      src/example/fuse/views/defStyle.ts
  55. 8 12
      src/example/fuse/views/overview/index.vue
  56. 2 2
      src/example/platform/platform-draw.ts

+ 1 - 1
package.json

@@ -1,7 +1,7 @@
 {
   "name": "drawing-board-service",
   "private": true,
-  "version": "1.1.0",
+  "version": "1.3.0",
   "type": "module",
   "scripts": {
     "dev:exe": "vite --mode=exedev",

+ 10 - 21
src/core/components/arrow/arrow.vue

@@ -6,6 +6,7 @@
     @update:position="updatePosition"
     @addPoint="addPoint"
     @deletePoint="deletePoint"
+    @delete="emit('delShape')"
     @update="emit('updateShape', { ...data })"
     canEdit
   />
@@ -21,7 +22,13 @@
 
 <script lang="ts" setup>
 import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
-import { ArrowData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
+import {
+  ArrowData,
+  getMouseStyle,
+  defaultStyle,
+  matResponse,
+  fixedStrokeOptions,
+} from "./index.ts";
 import { TempComponent } from "./";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
 import { Line } from "konva/lib/shapes/Line";
@@ -30,6 +37,7 @@ import { Group } from "konva/lib/Group";
 import { flatPositions } from "@/utils/shared.ts";
 import { themeColor } from "@/constant";
 import { watch, watchEffect } from "vue";
+import { useInstallStrokeWidthDescribe } from "@/core/hook/use-describe.ts";
 
 const props = defineProps<{ data: ArrowData }>();
 const emit = defineEmits<{
@@ -96,24 +104,5 @@ watch(
   { immediate: true }
 );
 
-watchEffect(() => {
-  if (zeroEq(lineLen(props.data.points[0], props.data.points[1]))) {
-    emit("delShape");
-  }
-});
-
-// const draw = useInteractiveDrawShapeAPI();
-// const store = useStore();
-// operateMenus.push({
-//   label: "钢笔编辑",
-//   handler() {
-//     draw.enterDrawShape("arrow", {
-//       ...props.data,
-//       getMessages: () => {
-//         const line = store.getItemById(props.data.id) as ArrowData;
-//         return line ? line.points : [];
-//       },
-//     });
-//   },
-// });
+useInstallStrokeWidthDescribe(describes, data, fixedStrokeOptions);
 </script>

+ 2 - 6
src/core/components/arrow/index.ts

@@ -16,6 +16,7 @@ export enum PointerPosition {
 }
 export const shapeName = "箭头";
 export const defaultStyle = {
+  fixed: true,
   fill: '#000000',
   pointerPosition: PointerPosition.end,
   strokeWidth: 5,
@@ -25,6 +26,7 @@ export const defaultStyle = {
 // export const fill
 
 export const addMode = "area";
+export const fixedStrokeOptions = [1, 2, 4];
 
 export const getMouseStyle = (data: ArrowData) => {
   const strokeStatus = getMouseColors(data.fill || defaultStyle.fill);
@@ -116,9 +118,3 @@ export const matResponse = ({data, mat, increment}: MatResponseProps<'arrow'>) =
   data.attitude = transfrom.copy().multiply(attitude).m;
   return data;
 }
-
-export const getPredefine = (key: keyof ArrowData) => {
-  if (key === 'strokeWidth') {
-    return { proportion: true }
-  }
-}

+ 28 - 4
src/core/components/arrow/temp-arrow.vue

@@ -9,7 +9,7 @@
         hitFunc: hitFunc,
         stroke: data.fill,
         fill: data.fill,
-        hitStrokeWidth: data.strokeWidth + 10,
+        hitStrokeWidth: data.strokeWidth + (data.fixed ? 10 * scale : 10),
         pointerWidth: data.pointerLength,
         closed: false,
         id: void 0,
@@ -47,15 +47,21 @@
       >
         <Point
           v-for="(_, ndx) in data.points"
-          :size="data.strokeWidth + 6"
+          :size="Math.max(props.data.strokeWidth || 10, 10)"
           :points="data.points"
+          :fixed="props.data.fixed"
           :ndx="ndx"
           :closed="false"
           :id="data.id"
           :disable="addMode"
           :color="data.fill"
           @update:position="(p) => emit('update:position', { ndx, val: p })"
-          @dragend="emit('update')"
+          @dragend="
+            () =>
+              zeroEq(lineLen(data.points[0], data.points[1]))
+                ? emit('delete')
+                : emit('update')
+          "
           notDelete
         />
       </template>
@@ -64,6 +70,7 @@
     <SizeLine
       v-if="config.showComponentSize"
       :points="data.points"
+      :fixed="data.fixed"
       :strokeWidth="data.strokeWidth"
       :stroke="data.fill"
     />
@@ -85,18 +92,35 @@ import { Group } from "konva/lib/Group";
 import { useConfig } from "@/core/hook/use-config.ts";
 import { useMouseShapeStatus } from "@/core/hook/use-mouse-status.ts";
 import { useOperMode } from "@/core/hook/use-status.ts";
+import { useFixedScale } from "@/core/hook/use-viewer.ts";
 
 const props = defineProps<{ data: ArrowData; canEdit?: boolean; addMode?: boolean }>();
 const emit = defineEmits<{
   (e: "update:position", data: { ndx: number; val: Pos }): void;
   (e: "update"): void;
+  (e: "delete"): void;
   (e: "deletePoint", ndx: number): void;
   (e: "addPoint", data: { ndx: number; val: Pos }): void;
 }>();
 
 const shape = ref<DC<Group>>();
 const config = useConfig();
-const data = computed(() => ({ ...defaultStyle, ...props.data }));
+const scale = useFixedScale();
+
+const data = computed(() => {
+  const style = {
+    ...defaultStyle,
+    ...props.data,
+  };
+  style.pointerLength = props.data.fixed
+    ? style.pointerLength * scale.value
+    : style.pointerLength;
+  style.strokeWidth = props.data.fixed
+    ? style.strokeWidth * scale.value
+    : style.strokeWidth;
+  console;
+  return style;
+});
 const hitFunc: LineConfig["hitFunc"] = (con, shape) => {
   con.beginPath();
   con.moveTo(data.value.points[0].x, data.value.points[0].y);

+ 4 - 1
src/core/components/circle/circle.vue

@@ -17,7 +17,7 @@
 </template>
 
 <script lang="ts" setup>
-import { CircleData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
+import { CircleData, getMouseStyle, defaultStyle, matResponse, fixedStrokeOptions } from "./index.ts";
 import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import TempCircle from "./temp-circle.vue";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
@@ -27,6 +27,7 @@ import { Ellipse } from "konva/lib/shapes/Ellipse";
 import { Pos } from "@/utils/math.ts";
 import { copy } from "@/utils/shared.ts";
 import { setShapeTransform } from "@/utils/shape.ts";
+import { useInstallStrokeWidthDescribe } from "@/core/hook/use-describe.ts";
 
 const props = defineProps<{ data: CircleData }>();
 const emit = defineEmits<{
@@ -97,4 +98,6 @@ const { shape, tData, data, operateMenus, describes } = useComponentStatus<
     // "ref", "zIndex"
   ],
 });
+useInstallStrokeWidthDescribe(describes, data, fixedStrokeOptions);
+
 </script>

+ 2 - 2
src/core/components/circle/index.ts

@@ -20,6 +20,7 @@ export const defaultStyle = {
   stroke: "#000000",
   strokeWidth: 5,
   fontSize: 22,
+  fixed: true,
   align: "center",
   fontStyle: "normal",
   fontColor: "#000000",
@@ -27,6 +28,7 @@ export const defaultStyle = {
 };
 
 export const addMode = "area";
+export const fixedStrokeOptions = [1, 2, 4];
 
 export const getMouseStyle = (data: CircleData) => {
   const fillStatus = data.fill && getMouseColors(data.fill);
@@ -143,7 +145,5 @@ export const matResponse = (
 export const getPredefine = (key: keyof CircleData) => {
   if (["fill", "stroke"].includes(key)) {
     return { canun: true };
-  } else if (key === "strokeWidth") {
-    return { proportion: true };
   }
 };

+ 12 - 1
src/core/components/circle/temp-circle.vue

@@ -53,6 +53,7 @@ import { DC } from "@/deconstruction.js";
 import { Circle } from "konva/lib/shapes/Circle";
 import { Transform } from "konva/lib/Util";
 import { useConfig } from "@/core/hook/use-config.ts";
+import { useFixedScale, useViewerInvertTransformConfig } from "@/core/hook/use-viewer.ts";
 
 const props = defineProps<{ data: CircleData; addMode?: boolean; editer?: boolean }>();
 const emit = defineEmits<{
@@ -61,7 +62,17 @@ const emit = defineEmits<{
 }>();
 
 const config = useConfig();
-const data = computed(() => ({ ...defaultStyle, ...props.data }));
+const scale = useFixedScale()
+const data = computed(() => {
+  const style = {
+    ...defaultStyle,
+    ...props.data,
+  };
+  if (style.fixed) {
+    style.strokeWidth *= scale.value;
+  }
+  return style;
+});
 
 const matConfig = computed(() => {
   const mat = new Transform(data.value.mat);

+ 2 - 0
src/core/components/icon/icon.ts

@@ -15,10 +15,12 @@ export const shapeName = "图例";
 export const defaultStyle = {
   coverFill: "#000000",
   coverOpcatiy: 0,
+  strokeWidth: 1,
   strokeScaleEnabled: false,
   width: 80,
   height: 80,
 };
+export const fixedStrokeOptions = [1, 2, 4];
 
 type ColorCounts = [string, number][];
 const colorsManage = (counts: ColorCounts, color: any) => {

+ 10 - 1
src/core/components/icon/icon.vue

@@ -12,7 +12,13 @@
 
 <script lang="ts" setup>
 import TempIcon from "./temp-icon.vue";
-import { IconData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
+import {
+  IconData,
+  getMouseStyle,
+  defaultStyle,
+  matResponse,
+  fixedStrokeOptions,
+} from "./index.ts";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
 import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import { Transform } from "konva/lib/Util";
@@ -20,6 +26,7 @@ import { useCustomTransformer } from "@/core/hook/use-transformer.ts";
 import { Group } from "konva/lib/Group";
 import { Rect } from "konva/lib/shapes/Rect";
 import { setShapeTransform } from "@/utils/shape.ts";
+import { useInstallStrokeWidthDescribe } from "@/core/hook/use-describe.ts";
 
 const props = defineProps<{ data: IconData }>();
 const emit = defineEmits<{
@@ -79,4 +86,6 @@ const { shape, tData, data, operateMenus, describes } = useComponentStatus({
   },
   propertys: ["name", "fill", "stroke", "strokeWidth"],
 });
+
+useInstallStrokeWidthDescribe(describes, data, fixedStrokeOptions, undefined, true);
 </script>

+ 1 - 0
src/core/components/image/index.ts

@@ -73,6 +73,7 @@ export const interactiveToData: InteractiveTo<"image"> = ({
   ...args
 }) => {
   if (info.cur) {
+    console.log(preset)
     return interactiveFixData({
       ...args,
       info,

+ 4 - 0
src/core/components/index.ts

@@ -4,6 +4,7 @@ import * as circle from "./circle";
 import * as triangle from "./triangle";
 import * as polygon from "./polygon";
 import * as line from "./line";
+import * as lineChunk from "./line-chunk";
 import * as lineIcon from "./line-icon/index";
 import * as text from "./text";
 import * as icon from "./icon";
@@ -22,6 +23,7 @@ import { CircleData } from "./circle";
 import { TriangleData } from "./triangle";
 import { PolygonData } from "./polygon";
 import { LineData } from "./line";
+import { LineChunkData } from "./line-chunk";
 import { LineIconData } from "./line-icon/index";
 import { TextData } from "./text";
 import { IconData } from "./icon";
@@ -43,6 +45,7 @@ const _components = {
   triangle,
   polygon,
   line,
+  lineChunk,
   lineIcon,
   text,
   icon,
@@ -94,6 +97,7 @@ export type DrawDataItem = {
   triangle: TriangleData;
   polygon: PolygonData;
   line: LineData;
+  lineChunk: LineChunkData;
   lineIcon: LineIconData,
   text: TextData;
   icon: IconData;

+ 121 - 0
src/core/components/line-chunk/index.ts

@@ -0,0 +1,121 @@
+import { inRevise, onlyId } from "@/utils/shared";
+import { InteractiveFix, InteractiveTo } from "..";
+import { LineData, generateUseDraw } from "../line";
+import { getBaseItem } from "../util";
+import { getMouseColors } from "@/utils/colors";
+import { SelectionManageBus, UseGetSelectionManage } from "@/core/hook/use-selection";
+import { useStore } from "@/core/store";
+import { EntityShape } from "@/deconstruction";
+import { Group } from "konva/lib/Group";
+import mitt from "mitt";
+import { watch } from "vue";
+
+export const shapeName = "线段";
+export const defaultStyle = {
+  strokeWidth: 3,
+  stroke: "#000000",
+  fixed: true,
+  dash: [30, 0],
+};
+
+export const fixedStrokeOptions = [1, 2, 4];
+export const useDraw = generateUseDraw('lineChunk');
+
+export const getMouseStyle = (data: LineData) => {
+  const strokeStatus = getMouseColors(data.stroke || defaultStyle.stroke);
+  const strokeWidth = data.strokeWidth || defaultStyle.strokeWidth;
+  return {
+    default: { stroke: data.stroke || defaultStyle.stroke, strokeWidth },
+    hover: { stroke: strokeStatus.hover },
+    select: { stroke: strokeStatus.select },
+    focus: { stroke: strokeStatus.hover },
+    press: { stroke: strokeStatus.press },
+  };
+};
+
+export const interactiveFixData: InteractiveFix<'lineChunk'> = ({ data, info }) => {
+  const nv = [...info.consumed, info.cur!];
+
+  data.points.length = nv.length;
+  for (let i = 0; i < nv.length; i++) {
+    if (inRevise(data.points[i], nv[i])) {
+      if (!data.points[i]) {
+        data.points[i] = {
+          id: onlyId(),
+          ...nv[i],
+        };
+      } else {
+        data.points[i] = {
+          ...data.points[i],
+          ...nv[i],
+        };
+      }
+    }
+  }
+  data.lines.length = nv.length - 1;
+  for (let i = 0; i < nv.length - 1; i++) {
+    if (!data.lines[i]) {
+      data.lines[i] = {
+        id: onlyId(),
+        ...defaultStyle,
+        a: data.points[i].id,
+        b: data.points[i + 1].id,
+      };
+    }
+  }
+
+  // data.polygon = [{points: [data.lines.map((item) => item.id)], id: onlyId()}];
+  return data;
+};
+
+export const interactiveToData: InteractiveTo<'lineChunk'> = ({
+  info,
+  preset = {},
+  ...args
+}) => {
+  if (info.cur) {
+    const baseItem = getBaseItem();
+    return interactiveFixData({
+      ...args,
+      info,
+      data: {
+        ...defaultStyle,
+        ...baseItem,
+        ...preset,
+        lines: [],
+        points: [],
+        polygon: [],
+      },
+    });
+  }
+};
+
+
+export const useGetSelectionManage: UseGetSelectionManage = () => {
+  const store = useStore();
+
+  const canSelect = (shape: EntityShape) => {
+    const id = shape.id();
+    const line = store.getTypeItems('lineChunk')[0];
+    return !!(id && line.lines.some((item) => item.id === id) && !(shape instanceof Group));
+  };
+  const listener = (shape: EntityShape) => {
+    const bus: SelectionManageBus = mitt();
+    const stop = watch(
+      () => canSelect(shape),
+      (exixts, _) => {
+        if (!exixts) {
+          bus.emit("del", shape);
+        }
+      },
+      { immediate: true }
+    );
+    return { stop, bus };
+  };
+
+  return { canSelect, listener };
+};
+
+
+export type LineChunkData = LineData;
+export * from "../line";

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

@@ -21,6 +21,7 @@ import {
   getSnapLine,
   getLineIconEndpoints,
   isRangInner,
+  fixedStrokeOptions,
 } from "./index.ts";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
 import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
@@ -48,6 +49,7 @@ import {
 } from "@/utils/math.ts";
 import { asyncTimeout, copy } from "@/utils/shared.ts";
 import { useTestPoints } from "@/core/hook/use-debugger.ts";
+import { useInstallStrokeWidthDescribe } from "@/core/hook/use-describe.ts";
 
 const props = defineProps<{ data: LineIconData }>();
 const emit = defineEmits<{
@@ -60,7 +62,6 @@ const store = useStore();
 const getOperType = useGetTransformerOperType();
 const viewMat = useViewerInvertTransform();
 const pos = usePointerPos();
-const testPoints = useTestPoints();
 const { shape, tData, data, operateMenus, describes } = useComponentStatus({
   emit,
   props,
@@ -256,4 +257,6 @@ if (props.data.type === "align-bottom" || props.data.type === "align-bottom-fix"
     }
   );
 }
+
+useInstallStrokeWidthDescribe(describes, data, fixedStrokeOptions, undefined, true);
 </script>

+ 2 - 0
src/core/components/line-icon/index.ts

@@ -22,6 +22,8 @@ import { DrawStore } from "@/core/store/index.ts";
 export { defaultStyle, addMode, TempComponent, Component };
 export { getMouseStyle, getPredefine } from "../icon/index.ts";
 
+export const fixedStrokeOptions = [1, 2, 4];
+
 export const shapeName = "线段图例";
 export type LineIconData = Omit<IconData, "mat" | "width"> & {
   startLen: number;

+ 78 - 51
src/core/components/line/attach-server.ts

@@ -50,6 +50,7 @@ import {
 } from "../line-icon";
 import { useDrawIngData } from "@/core/hook/use-draw";
 import { useComponentDescribes } from "@/core/hook/use-component";
+import { useInstallStrokeWidthDescribe } from "@/core/hook/use-describe";
 
 export type NLineDataCtx = {
   del: {
@@ -161,20 +162,23 @@ export const getJoinLine = (
     });
 };
 
-export const foreNormalLineData = (data:LineData) => {
+export const foreNormalLineData = (data: LineData) => {
   for (let i = 0; i < data.lines.length; i++) {
-    const {a, b} = data.lines[i]
-    if (!data.points.some(p => p.id === a) || !data.points.some(p => p.id === b)) {
-      data.lines.splice(i--, 1)
+    const { a, b } = data.lines[i];
+    if (
+      !data.points.some((p) => p.id === a) ||
+      !data.points.some((p) => p.id === b)
+    ) {
+      data.lines.splice(i--, 1);
     }
   }
   for (let i = 0; i < data.points.length; i++) {
-    const id = data.points[i].id
-    if (!data.lines.some(l => l.a === id || l.b === id)) {
-      data.points.splice(i, 1)
+    const id = data.points[i].id;
+    if (!data.lines.some((l) => l.a === id || l.b === id)) {
+      data.points.splice(i, 1);
     }
   }
-}
+};
 
 export const normalLineData = (data: LineData, ctx: NLineDataCtx) => {
   const changePoints = [
@@ -339,6 +343,7 @@ export const genMoveLineHandler = (
           ...getBaseItem(),
           ...defaultStyle,
           a: point.id,
+          fixed: true,
           b: newPoint.id,
         };
         data.lines.push(newLine);
@@ -493,10 +498,10 @@ export const genMoveLineHandler = (
   };
 };
 
-export const useLineDataSnapInfos = () => {
+export const useLineDataSnapInfos = (type: "line" | "lineChunk") => {
   const infos = useCustomSnapInfos();
   const store = useStore();
-  const lineData = computed(() => store.getTypeItems("line")[0]);
+  const lineData = computed(() => store.getTypeItems(type)[0]);
   let snapInfos: ComponentSnapInfo[];
 
   const updateSnapInfos = (pointIds: string[]) => {
@@ -580,54 +585,74 @@ export const updateLineLength = (
   Object.assign(points[1], npoints[1]);
 };
 
-export const useLineDescribes = (line: Ref<LineDataLine>) => {
+export const useLineDescribes = (
+  line: Ref<LineDataLine>,
+  type: "line" | "lineChunk",
+  fixedStroke = false,
+  fixedStrokeOptions: number[] = []
+) => {
   const d: any = useComponentDescribes(line, ["stroke", "strokeWidth"], {});
   const store = useStore();
-  const lineData = computed(() => store.getTypeItems("line")[0]);
+  const lineData = computed(() => store.getTypeItems(type)[0]);
   const points = computed(() => [
     lineData.value.points.find((p) => p.id === line.value.a)!,
     lineData.value.points.find((p) => p.id === line.value.b)!,
   ]);
   let setLineVector: Vector2;
 
-  watch(d, (d) => {
-    d.strokeWidth.props = {
-      ...d.strokeWidth.props,
-      proportion: true,
-    };
-    d.strokeWidth.label = "粗细";
-    d.stroke.label = "颜色";
-
-  d.length = {
-    type: "inputNum",
-    label: "线段长度",
-    "layout-type": "row",
-    props: {
-      proportion: true,
-    },
-    
-    get value() {
-      return lineLen(points.value[0], points.value[1]);
-    },
-    set value(val) {
-      console.log(val, d.length.isChange);
-      if (!d.isChange) {
-        setLineVector = lineVector(points.value);
-      }
-      updateLineLength(
-        lineData.value,
-        line.value,
-        val,
-        undefined,
-        setLineVector
-      );
+  if (fixedStroke) {
+    watch(
+      d,
+      (d) => {
+        d.strokeWidth.label = "厚度";
+        d.strokeWidth.props = {
+          ...d.strokeWidth.props,
+          proportion: true,
+        };
+      },
+      { immediate: true }
+    );
+  } else {
+    useInstallStrokeWidthDescribe(d, line, fixedStrokeOptions);
+  }
+  
+  watch(
+    d,
+    (d) => {
+      d.stroke.label = "颜色";
+      d.length = {
+        type: "inputNum",
+        label: "长度",
+        "layout-type": "row",
+        props: {
+          proportion: true,
+        },
+
+        get value() {
+          return lineLen(points.value[0], points.value[1]);
+        },
+        set value(val) {
+          console.log(val, d.length.isChange);
+          if (!d.isChange) {
+            setLineVector = lineVector(points.value);
+          }
+          updateLineLength(
+            lineData.value,
+            line.value,
+            val,
+            undefined,
+            setLineVector
+          );
+        },
+      };
     },
-  };
-  }, {immediate: true});
-  return d as PropertyDescribes;
+    { immediate: true }
+  );
+  return d as Ref<PropertyDescribes>;
 };
 
 export const useDrawLinePoint = (
+  type: "line" | "lineChunk",
   data: Ref<LineData>,
   line: Ref<LineDataLine>,
   callback: (data: {
@@ -659,18 +684,20 @@ export const useDrawLinePoint = (
     point: LineData["points"][0];
   }>();
   const runHook = useRunHook();
-  const snapInfos = useLineDataSnapInfos();
+  const store = useStore();
+
+  const snapInfos = useLineDataSnapInfos(type);
   const snap = useSnap();
   const stage = useStage();
-  const store = useStore();
   const icons = computed(() =>
-    store.getTypeItems("lineIcon").filter((item) => item.lineId === line.value.id)
+    store
+      .getTypeItems("lineIcon")
+      .filter((item) => item.lineId === line.value.id)
   );
   const drawStore = useDrawIngData();
   const cursor = useCursor();
   const enterDraw = () => {
-    const points = getLinePoints(data.value, line.value)
-    console.log(points, data.value, line.value)
+    const points = getLinePoints(data.value, line.value);
     const cdata: LineData = { ...data.value, points, lines: [] };
     const point = reactive({ ...lineCenter(points), id: onlyId() });
     const cIcons = icons.value.map((icon) => ({ ...icon, id: onlyId() }));

+ 8 - 3
src/core/components/line/index.ts

@@ -2,7 +2,7 @@ import { lineVector, Pos, vectorAngle, verticalVector } from "@/utils/math.ts";
 import { BaseItem, generateSnapInfos, getBaseItem } from "../util.ts";
 import { getMouseColors } from "@/utils/colors.ts";
 import { InteractiveFix, InteractiveTo, MatResponseProps } from "../index.ts";
-import { copy, inRevise, onlyId, rangMod } from "@/utils/shared.ts";
+import { inRevise, onlyId, rangMod } from "@/utils/shared.ts";
 import { MathUtils } from "three";
 import { DrawStore, useStore } from "@/core/store/index.ts";
 import {
@@ -15,15 +15,19 @@ import { Ref, ref, watch } from "vue";
 import { getInitCtx, NLineDataCtx, normalLineData } from "./attach-server.ts";
 import * as wallRenderer from "./renderer/wall";
 import { Group } from "konva/lib/Group";
+import { generateUseDraw } from "./use-draw.ts";
 
 export { default as Component } from "./line.vue";
 export { default as TempComponent } from "./temp-line.vue";
-export { useDraw } from "./use-draw.ts";
+export { generateUseDraw } from "./use-draw.ts";
 
-export const shapeName = "线段";
+export const useDraw = generateUseDraw("line");
+
+export const shapeName = "墙";
 export const defaultStyle = {
   stroke: "#000000",
   strokeWidth: 20,
+  fixed: true,
   dash: [30, 0],
 };
 
@@ -80,6 +84,7 @@ export type LineDataLine = {
   id: string;
   a: string;
   b: string;
+  fixed: boolean
   strokeWidth: number;
   stroke: string;
   dash: number[];

+ 1 - 1
src/core/components/line/line.vue

@@ -1,5 +1,5 @@
 <template>
-  <TempLine :data="data" @updateShape="emit('updateShape', data)" />
+  <TempLine :data="data" @updateShape="emit('updateShape', data)"  />
 </template>
 
 <script lang="ts" setup>

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

@@ -7,6 +7,8 @@
       fill: stroke,
       closed: true,
       listening: false,
+      stroke: border ? '#000000' : undefined,
+      strokeWidth: border ? strokeWidth : undefined,
     }"
   />
 
@@ -15,28 +17,23 @@
       <template v-if="gd.steps.value.length">
         <SizeLine
           :points="line"
-          :strokeWidth="props.line.strokeWidth"
-          :stroke="props.line.stroke"
-          v-for="line in [...gd.steps.value, ...gd.subSteps.value]"
+          :fixed="props.line.fixed"
+          v-for="(line, i) in [...gd.steps.value, ...gd.subSteps.value]"
         />
       </template>
-      <SizeLine
-        :points="points"
-        :strokeWidth="props.line.strokeWidth"
-        :stroke="props.line.stroke"
-        v-else
-      />
+      <SizeLine :points="points" :fixed="props.line.fixed" v-else />
     </v-group>
   </template>
 </template>
 
 <script lang="ts" setup>
-import { computed } from "vue";
+import { computed, watch, watchEffect } from "vue";
 import { useGetDiffLineIconPolygons, useGetExtendPolygon } from "./view";
 import { LineData, LineDataLine } from "../..";
 import { getLinePoints } from "../../attach-server";
 import { flatPositions } from "@/utils/shared";
 import SizeLine from "../../../share/size-line.vue";
+import { useFixedScale } from "@/core/hook/use-viewer";
 
 const props = defineProps<{
   getShapeAttrib: ReturnType<typeof useGetExtendPolygon>;
@@ -45,10 +42,13 @@ const props = defineProps<{
   opacity?: number;
   stroke?: string;
   showLabel: any;
+  border?: boolean;
 }>();
 
 const polygon = computed(() => props.getShapeAttrib(props.line));
 const points = computed(() => getLinePoints(props.data, props.line));
 const gd = useGetDiffLineIconPolygons(props.line, points);
 const polygons = computed(() => gd.diff(polygon.value));
+const scale = useFixedScale();
+const strokeWidth = computed(() => (props.line.fixed ? scale.value * 1 : 1));
 </script>

+ 25 - 15
src/core/components/line/renderer/wall/view.ts

@@ -6,7 +6,6 @@ import {
   getLineEdges,
   LEJInfo,
   LEJLine,
-  lineLen,
   lineVector,
   Pos,
   verticalVector,
@@ -20,6 +19,7 @@ import { computed, nextTick, reactive, Ref, watch } from "vue";
 import { getLineIconEndpoints } from "../../../line-icon";
 import { useDrawIngData } from "@/core/hook/use-draw";
 import { polygonDifference, polygonDifferenceOnly } from "@/utils/math-clip";
+import { useFixedScale } from "@/core/hook/use-viewer";
 
 export const useGetExtendPolygon = (lineData: Ref<LineData | undefined>) => {
   const minAngle = MathUtils.degToRad(0.1);
@@ -28,8 +28,13 @@ export const useGetExtendPolygon = (lineData: Ref<LineData | undefined>) => {
   type JInfo = { lej: LEJInfo | undefined; diffPolygons?: Pos[][] };
   const joinInfos = reactive({}) as Record<string, Record<string, JInfo>>;
 
+  const scale = useFixedScale();
+  const getWidth = (width: number, fixed: boolean) =>
+    fixed ? width * scale.value : width;
+
   const getInfoKey = (line: LEJLine) =>
-    line.points.reduce((t, p) => round(p.x, 3) + round(p.y, 3) + t, "") + line.width;
+    line.points.reduce((t, p) => round(p.x, 3) + round(p.y, 3) + t, "") +
+    line.width;
 
   const setLEJInfo = (
     data: LineData,
@@ -38,11 +43,11 @@ export const useGetExtendPolygon = (lineData: Ref<LineData | undefined>) => {
   ) => {
     const origin = {
       points: getLinePoints(data, originLine),
-      width: originLine.strokeWidth,
+      width: getWidth(originLine.strokeWidth, originLine.fixed),
     };
     const target = {
       points: getLinePoints(data, targetLine),
-      width: targetLine.strokeWidth,
+      width: getWidth(targetLine.strokeWidth, targetLine.fixed),
     };
     const { originNdx } = getLEJJoinNdxs(origin.points, target.points);
     const lej = getLineEdgeJoinInfo(origin, target, minAngle, palAngle);
@@ -60,7 +65,7 @@ export const useGetExtendPolygon = (lineData: Ref<LineData | undefined>) => {
   const getLEJPolygon = (data: LineData, originLine: LineDataLine) => {
     const origin = {
       points: getLinePoints(data, originLine),
-      width: originLine.strokeWidth,
+      width: getWidth(originLine.strokeWidth, originLine.fixed),
     };
     if (!origin.points[0] || !origin.points[1]) return [];
     const key = getInfoKey(origin);
@@ -118,8 +123,8 @@ export const useGetExtendPolygon = (lineData: Ref<LineData | undefined>) => {
     };
 
     let diffPolygons: Pos[][] = [];
-    const pointIds = lines.flatMap(l => [l.a, l.b])
-    const lineCount = lines.length
+    const pointIds = lines.flatMap((l) => [l.a, l.b]);
+    const lineCount = lines.length;
     while (lines.length) {
       if (lines.length > 1) {
         const select = selectLEJLines(lines)!;
@@ -129,8 +134,8 @@ export const useGetExtendPolygon = (lineData: Ref<LineData | undefined>) => {
         lines = lines.filter(
           (line) => line !== select.origin && line !== select.target
         );
-        origin.diffPolygons = diffPolygons
-        target.diffPolygons = diffPolygons
+        origin.diffPolygons = diffPolygons;
+        target.diffPolygons = diffPolygons;
 
         diffPolygons = [
           ...diffPolygons,
@@ -140,13 +145,13 @@ export const useGetExtendPolygon = (lineData: Ref<LineData | undefined>) => {
       } else {
         const key = getInfoKey({
           points: getLinePoints(data, lines[0]),
-          width: lines[0].strokeWidth,
+          width: getWidth(lines[0].strokeWidth, lines[0].fixed),
         });
         if (!(key in joinInfos)) {
           joinInfos[key] = {};
         }
         const ndx = [lines[0].a, lines[0].b].findIndex(
-          (id) => pointIds.filter(pid => id === pid).length === lineCount
+          (id) => pointIds.filter((pid) => id === pid).length === lineCount
         );
         joinInfos[key][ndx] = { lej: undefined, diffPolygons };
         lines = [];
@@ -156,7 +161,7 @@ export const useGetExtendPolygon = (lineData: Ref<LineData | undefined>) => {
 
   const genLEJLine = (lineData: LineData, line: LineDataLine) => ({
     points: getLinePoints(lineData, line),
-    width: line.strokeWidth,
+    width: getWidth(line.strokeWidth, line.fixed),
   });
 
   const init = (data: LineData) => {
@@ -208,7 +213,7 @@ export const useGetExtendPolygon = (lineData: Ref<LineData | undefined>) => {
             delete joinInfos[key];
           });
         },
-        { immediate: true, flush: 'post' }
+        { immediate: true, flush: "post" }
       );
     };
 
@@ -254,7 +259,7 @@ export const useGetExtendPolygon = (lineData: Ref<LineData | undefined>) => {
   return (line: LineDataLine) => {
     // console.error(lineLen(...getLinePoints(lineData.value!, line!)))
     const polygon = lineData.value ? getLEJPolygon(lineData.value, line) : [];
-    return polygon
+    return polygon;
   };
 };
 
@@ -354,10 +359,15 @@ export const useGetDiffLineIconPolygons = (
     });
   });
 
+  const scale = useFixedScale();
+  const width = computed(() =>
+    line.fixed ? line.strokeWidth * scale.value : line.strokeWidth
+  );
+
   const interPolygons = computed(() => {
     return interLines.value.map((il) => {
       const interLine = il.points;
-      const topOffset = linevv.value.clone().multiplyScalar(line.strokeWidth);
+      const topOffset = linevv.value.clone().multiplyScalar(width.value);
       const botOffset = topOffset.clone().multiplyScalar(-1);
       return [
         topOffset.clone().add(interLine[0]),

+ 20 - 6
src/core/components/line/single-line.vue

@@ -30,6 +30,7 @@
     :getShapeAttrib="getShapeAttrib"
     :data="data"
     :line="line"
+    :border="type === 'line'"
     :showLabel="
       active ||
       config.showComponentSize ||
@@ -56,23 +57,27 @@
 
   <template v-if="drawProps">
     <SingleLine
+      :type="type"
       :data="drawProps.data"
       :line="drawProps.prev"
       :drawMode="drawProps.point"
       :getShapeAttrib="drawGetShapeAttrib"
     />
     <singlePoint
+      :type="type"
       :data="drawProps.data"
       :line="drawProps.prev"
       :drawMode="drawProps.point"
     />
     <SingleLine
+      :type="type"
       :data="drawProps.data"
       :line="drawProps.next"
       :drawMode="drawProps.point"
       :getShapeAttrib="drawGetShapeAttrib"
     />
     <singlePoint
+      :type="type"
       :data="drawProps.data"
       :line="drawProps.next"
       :drawMode="drawProps.point"
@@ -84,7 +89,7 @@
 import EditLine from "../share/edit-line.vue";
 import singlePoint from "./single-point.vue";
 import { computed, ref } from "vue";
-import { getMouseStyle, LineData, LineDataLine, shapeName, renderer } from "./index.ts";
+import { getMouseStyle, LineData, LineDataLine, renderer } from "./index.ts";
 import { onlyId } from "@/utils/shared.ts";
 import { Pos } from "@/utils/math.ts";
 import { Line } from "konva/lib/shapes/Line";
@@ -105,10 +110,13 @@ import {
 import { useStore } from "@/core/store/index.ts";
 import { useHistory } from "@/core/hook/use-history.ts";
 import { useTransformIngShapes } from "@/core/hook/use-global-vars.ts";
+import { components } from "../index.ts";
+import { fixedStrokeOptions } from "../line-chunk/index.ts";
 
 const props = defineProps<{
   line: LineDataLine;
   addMode?: boolean;
+  type: "line" | "lineChunk";
   canEdit?: boolean;
   data: LineData;
   dragPointIds?: string[];
@@ -116,6 +124,8 @@ const props = defineProps<{
   getShapeAttrib?: (line: LineDataLine) => any;
 }>();
 
+const shapeName = computed(() => components[props.type].shapeName);
+
 const emit = defineEmits<{
   (e: "updatePoint", value: LineData["points"][number]): void;
   (e: "addPoint", value: LineData["points"][number]): void;
@@ -135,8 +145,13 @@ const points = computed(() => getLinePoints(props.data, props.line));
 
 const shape = ref<DC<Line>>();
 const lineData = computed(() => props.line);
-const describes = useLineDescribes(lineData);
 
+const describes = useLineDescribes(
+  lineData,
+  props.type,
+  props.type !== "lineChunk",
+  fixedStrokeOptions
+);
 const delHandler = () => {
   emit("updateBefore", [props.line.a, props.line.b]);
   emit("delLine");
@@ -146,6 +161,7 @@ const delHandler = () => {
 const store = useStore();
 const history = useHistory();
 const { drawProps, enter: enterDrawLinePoint } = useDrawLinePoint(
+  props.type,
   computed(() => props.data),
   computed(() => props.line),
   (data) => {
@@ -163,9 +179,7 @@ const { drawProps, enter: enterDrawLinePoint } = useDrawLinePoint(
 );
 
 const drawData = computed(() => drawProps.value?.data);
-const drawGetShapeAttrib = computed(
-  () => renderer.value && renderer.value.genGetShapeAttrib(drawData)
-);
+const drawGetShapeAttrib = renderer.value!.genGetShapeAttrib(drawData);
 const menus = [
   { label: "加点", handler: enterDrawLinePoint },
   { label: "删除", handler: delHandler },
@@ -203,7 +217,7 @@ const addPoint = (pos: Pos) => {
   emit("update");
 };
 
-const lDataSnap = useLineDataSnapInfos();
+const lDataSnap = useLineDataSnapInfos(props.type);
 const config = useConfig();
 const dragstartHandler = (eIds: string[]) => {
   emit("updateBefore", eIds);

+ 3 - 1
src/core/components/line/single-point.vue

@@ -10,6 +10,7 @@
       :ndx="ndx"
       :closed="false"
       :id="line.id"
+      :fixed="line.fixed"
       :disable="addMode || !!drawMode"
       :color="isDrawIng ? themeColor : style.stroke"
       @dragstart="dragstartHandler([point.id])"
@@ -33,6 +34,7 @@ import { Circle } from "konva/lib/shapes/Circle";
 
 const props = defineProps<{
   lineShape?: DC<Line>;
+  type: 'line' | 'lineChunk';
   line: LineData["lines"][number];
   addMode?: boolean;
   data: LineData;
@@ -87,7 +89,7 @@ const delPoint = (point: LineData["points"][number]) => {
   emit("update");
 };
 
-const lDataSnap = useLineDataSnapInfos();
+const lDataSnap = useLineDataSnapInfos(props.type);
 const dragIng = ref(false);
 const dragstartHandler = (eIds: string[]) => {
   emit("updateBefore", eIds);

+ 8 - 4
src/core/components/line/temp-line.vue

@@ -7,6 +7,7 @@
         :key="item.id"
         :line="item"
         :data="data"
+        :type="type"
         :add-mode="addMode"
         :can-edit="!initData && !operMode.mulSelection"
         :dragPointIds="dragPointIds"
@@ -27,6 +28,7 @@
         v-for="(item, ndx) in data.lines"
         :line-shape="lineShapes[ndx]"
         :dragPointIds="dragPointIds"
+        :type="type"
         :key="item.id"
         :line="item"
         :data="data"
@@ -60,6 +62,7 @@ import { useMouseShapeStatus } from "@/core/hook/use-mouse-status.ts";
 import { Pos } from "@/utils/math.ts";
 import { useSnapConfig, useSnapResultInfo } from "@/core/hook/use-snap.ts";
 import { Line } from "konva/lib/shapes/Line";
+import { useStore } from "@/core/store/index.ts";
 
 const props = defineProps<{
   data: LineData;
@@ -68,7 +71,10 @@ const props = defineProps<{
 }>();
 
 const operMode = useOperMode();
-const initData = useInitData();
+const store = useStore();
+const type = computed(() => store.getType(props.data.id) as "line" | "lineChunk");
+const initData = useInitData(type.value);
+
 const emit = defineEmits<{
   (e: "updateShape"): void;
 }>();
@@ -78,9 +84,7 @@ const data = computed(() => {
   if (!initData.value || props.addMode) return props.data;
   return initData.value;
 });
-const getShapeAttrib = computed(
-  () => renderer.value && renderer.value.genGetShapeAttrib(data)
-);
+const getShapeAttrib = renderer.value!.genGetShapeAttrib(data);
 
 const dragPointIds = ref<string[]>();
 let track = false;

+ 27 - 10
src/core/components/line/use-draw.ts

@@ -5,14 +5,14 @@ import {
   useInteractiveDrawShapeAPI,
   usePointBeforeHandler,
 } from "@/core/hook/use-draw";
-import { components, ComponentSnapInfo, SnapPoint } from "..";
+import { components, ComponentSnapInfo, ShapeType, SnapPoint } from "..";
 import { useHistory, useHistoryAttach } from "@/core/hook/use-history";
 import { useStore } from "@/core/store";
 import { useViewerTransform } from "@/core/hook/use-viewer";
 import { useOperMode } from "@/core/hook/use-status";
 import { installGlobalVar, useCursor } from "@/core/hook/use-global-vars";
 import { useInteractiveDots } from "@/core/hook/use-interactive";
-import { computed, nextTick, reactive, ref, watch } from "vue";
+import { computed, nextTick, reactive, ref, watch, watchEffect } from "vue";
 import { copy, mergeFuns } from "@/utils/shared";
 import { lineVector, Pos } from "@/utils/math";
 import { getSnapInfos, type LineData } from "./";
@@ -23,11 +23,23 @@ import { useProportion } from "@/core/hook/use-proportion";
 
 type PayData = Pos;
 
-export let initData: LineData | undefined;
-export const useInitData = installGlobalVar(() => ref<LineData>());
+const useTypeInitData = installGlobalVar(() =>
+  ref<Record<string, LineData | undefined>>({})
+);
+export const useInitData = (type: string) => {
+  const allInitData = useTypeInitData();
+  return computed({
+    get: () => allInitData.value[type],
+    set: (value) => (allInitData.value[type] = value),
+  });
+};
 
-export const useDraw = () => {
-  const type = "line";
+export const generateUseDraw = (type: "line" | "lineChunk" = "line") => {
+  console.log("generateUseDraw", type);
+  return () => useDraw(type);
+};
+
+const useDraw = (type: "line" | "lineChunk" = "line") => {
   const { quitDrawShape } = useInteractiveDrawShapeAPI();
   const isRuning = useDrawRunning(type);
   const obj = components[type];
@@ -36,9 +48,10 @@ export const useDraw = () => {
   const store = useStore();
   const viewTransform = useViewerTransform();
   const operMode = useOperMode();
-  const hInitData = useInitData();
+  const hInitData = useInitData(type);
   const customSnapInfos = useCustomSnapInfos();
-  const { invTransform } = useProportion()
+  const { invTransform } = useProportion();
+  let initData: LineData | undefined;
 
   // 可能历史空间会撤销 重做更改到正在绘制的组件
   const currentCursor = ref("./icons/m_add.png");
@@ -55,12 +68,14 @@ export const useDraw = () => {
     shapeType: type,
     isRuning,
     enter() {
+      console.log("enter, ", type);
       cursorPop = cursor.push(currentCursor.value);
       watch(currentCursor, () => {
         cursorPop?.set(currentCursor.value);
       });
     },
     quit: () => {
+      console.log("quit, ", type);
       quitDrawShape();
       beforeHandler.clear();
       cursorPop && cursorPop();
@@ -254,7 +269,7 @@ export const useDraw = () => {
     const keyInput = getKeywordInput(
       (inputData, prev) => {
         const len = Number(inputData);
-        
+
         if (len && drawItems[0].lines.length) {
           const line = drawItems[0].lines[drawItems[0].lines.length - 1];
           const points = [
@@ -262,7 +277,9 @@ export const useDraw = () => {
             drawItems[0].points.find((p) => p.id === line.b)!,
           ];
           const vector = lineVector(points);
-          const position = vector.multiplyScalar(invTransform(len)).add(points[0]);
+          const position = vector
+            .multiplyScalar(invTransform(len))
+            .add(points[0]);
           cur.x = position.x;
           cur.y = position.y;
           isInputChange = true;

+ 2 - 2
src/core/components/polygon/index.ts

@@ -9,8 +9,10 @@ export { default as Component } from "./polygon.vue";
 export { default as TempComponent } from "./temp-polygon.vue";
 
 export const shapeName = "多边形";
+export const fixedStrokeOptions = [1, 2, 4];
 export const defaultStyle = {
   stroke: "#000000",
+  fixed: true,
   strokeWidth: 5,
   dash: [30, 0],
 };
@@ -111,7 +113,5 @@ export const matResponse = ({
 export const getPredefine = (key: keyof PolygonData) => {
   if (["fill", "stroke"].includes(key)) {
     return { canun: true };
-  } else if (key === "strokeWidth") {
-    return { proportion: true };
   }
 };

+ 9 - 1
src/core/components/polygon/polygon.vue

@@ -20,13 +20,20 @@
 </template>
 
 <script lang="ts" setup>
-import { PolygonData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
+import {
+  PolygonData,
+  getMouseStyle,
+  defaultStyle,
+  matResponse,
+  fixedStrokeOptions,
+} from "./index.ts";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
 import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import TempLine from "./temp-polygon.vue";
 import { useInteractiveDrawShapeAPI } from "@/core/hook/use-draw.ts";
 import { useStore } from "@/core/store/index.ts";
 import { Pos } from "@/utils/math.ts";
+import { useInstallStrokeWidthDescribe } from "@/core/hook/use-describe.ts";
 
 const props = defineProps<{ data: PolygonData }>();
 const emit = defineEmits<{
@@ -86,4 +93,5 @@ operateMenus.push({
     });
   },
 });
+useInstallStrokeWidthDescribe(describes, data, fixedStrokeOptions);
 </script>

+ 13 - 1
src/core/components/polygon/temp-polygon.vue

@@ -17,6 +17,7 @@
       :shape="shape"
       :addMode="addMode"
       closed
+      :fixed="data.fixed"
       :canEdit="canEdit"
       @update:position="(data) => emit('update:position', data)"
       @update="emit('update')"
@@ -45,6 +46,7 @@ import { DC } from "@/deconstruction.js";
 import { Line } from "konva/lib/shapes/Line";
 import { Pos } from "@/utils/math.ts";
 import { useConfig } from "@/core/hook/use-config.ts";
+import { useFixedScale } from "@/core/hook/use-viewer.ts";
 const props = defineProps<{ data: PolygonData; canEdit?: boolean; addMode?: boolean }>();
 const emit = defineEmits<{
   (e: "update:position", data: { ndx: number; val: Pos }): void;
@@ -53,7 +55,17 @@ const emit = defineEmits<{
   (e: "deletePoint", ndx: number): void;
 }>();
 
-const data = computed(() => ({ ...defaultStyle, ...props.data }));
+const scale = useFixedScale();
+const data = computed(() => {
+  const style = {
+    ...defaultStyle,
+    ...props.data,
+  };
+  if (style.fixed) {
+    style.strokeWidth *= scale.value;
+  }
+  return style;
+});
 const shape = ref<DC<Line>>();
 const config = useConfig();
 

+ 2 - 3
src/core/components/rectangle/index.ts

@@ -11,6 +11,7 @@ export { default as TempComponent } from "./temp-rectangle.vue";
 export const shapeName = "矩形";
 export const defaultStyle = {
   dash: [30, 0],
+  fixed: true,
   strokeWidth: 5,
   stroke: "#000000",
   fontSize: 22,
@@ -18,6 +19,7 @@ export const defaultStyle = {
   fontStyle: "normal",
   fontColor: "#000000",
 };
+export const fixedStrokeOptions = [1, 2, 4];
 
 export const getMouseStyle = (data: RectangleData) => {
   const fillStatus = data.fill && getMouseColors(data.fill);
@@ -124,8 +126,5 @@ export const getPredefine = (key: keyof RectangleData) => {
 
   if (["fill", "stroke"].includes(key)) {
     return { canun: true };
-  } else if (key === "strokeWidth") {
-    return { proportion: true };
   }
-
 };

+ 3 - 1
src/core/components/rectangle/rectangle.vue

@@ -16,10 +16,11 @@
 </template>
 
 <script lang="ts" setup>
-import { RectangleData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
+import { RectangleData, getMouseStyle, defaultStyle, matResponse, fixedStrokeOptions } from "./index.ts";
 import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import TempLine from "./temp-rectangle.vue";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
+import { useInstallStrokeWidthDescribe } from "@/core/hook/use-describe.ts";
 
 const props = defineProps<{ data: RectangleData }>();
 const emit = defineEmits<{
@@ -60,4 +61,5 @@ const { shape, tData, data, operateMenus, describes } = useComponentStatus({
     // "ref", "zIndex"
   ],
 });
+useInstallStrokeWidthDescribe(describes, data, fixedStrokeOptions);
 </script>

+ 13 - 2
src/core/components/rectangle/temp-rectangle.vue

@@ -14,7 +14,7 @@
     <ShareText
       :config="{ ...textConfig, ...textBound }"
       :parent-id="data.id"
-      :editer="editer&& !data.disableEditText"
+      :editer="editer && !data.disableEditText"
       @update-text="(val) => emit('updateContent', val)"
       @update:is-edit="(val) => emit('update:isEdit', val)"
     />
@@ -39,6 +39,7 @@ import { Line } from "konva/lib/shapes/Line";
 import { Transform } from "konva/lib/Util";
 import { MathUtils } from "three";
 import { useConfig } from "@/core/hook/use-config.ts";
+import { useFixedScale, useViewerInvertTransformConfig } from "@/core/hook/use-viewer.ts";
 
 const props = defineProps<{ data: RectangleData; addMode?: boolean; editer?: boolean }>();
 const emit = defineEmits<{
@@ -47,7 +48,17 @@ const emit = defineEmits<{
 }>();
 
 const config = useConfig();
-const data = computed(() => ({ ...defaultStyle, ...props.data }));
+const scale = useFixedScale();
+const data = computed(() => {
+  const style = {
+    ...defaultStyle,
+    ...props.data,
+  };
+  if (style.fixed) {
+    style.strokeWidth *= scale.value;
+  }
+  return style;
+});
 const textBound = computed(() => {
   const dec = new Transform(props.data.attitude).decompose();
   const inv = new Transform().rotate(MathUtils.degToRad(-dec.rotation));

+ 19 - 6
src/core/components/share/edit-line.vue

@@ -3,12 +3,12 @@
     ref="line"
     :config="{
       id: id,
-      strokeWidth: data.strokeWidth,
+      strokeWidth: width,
       opacity: opacity || 0,
       stroke: data.stroke,
       zIndex: zIndex,
       points: flatPositions(points),
-      hitStrokeWidth: data.strokeWidth,
+      hitStrokeWidth: hitWidth,
     }"
   />
 
@@ -39,12 +39,18 @@ import { generateSnapInfos } from "../util";
 import { getMouseColors } from "@/utils/colors";
 import { themeColor } from "@/constant";
 import { Circle } from "konva/lib/shapes/Circle";
-import { SLineData } from "../sequent-line";
-import { useViewer } from "@/core/hook/use-viewer";
+import {
+  useFixedScale,
+  useViewer,
+  useViewerInvertTransformConfig,
+} from "@/core/hook/use-viewer";
 import { useMode } from "@/core/hook/use-status";
 import { Mode } from "@/constant/mode";
+import { LineDataLine } from "../line";
+
+type LData = Pick<LineDataLine, "strokeWidth" | "stroke"> & { fixed?: boolean };
 
-type LData = Pick<SLineData, "strokeWidth" | "stroke">;
+const scale = useFixedScale();
 const props = defineProps<{
   data: LData;
   points: Pos[];
@@ -162,9 +168,16 @@ useShapeClick(point, () => {
   addCursorPop();
 });
 const center = computed(() => lineCenter(points.value));
+const width = computed(() =>
+  props.data.fixed ? props.data.strokeWidth * scale.value : props.data.strokeWidth
+);
+const hitWidth = computed(() => {
+  const hitWidth = Math.max(props.data.strokeWidth || 0, 10);
+  return props.data.fixed ? hitWidth * scale.value : hitWidth;
+});
 const pointStyle = computed(() => {
   const color = getMouseColors(props.data.stroke || themeColor);
-  const size = (props.data.strokeWidth || 1) + 6 || 5;
+  const size = (width.value || 1) + 6 || 5;
   return {
     radius: size / 2,
     fill: "#fff",

+ 10 - 3
src/core/components/share/edit-point.vue

@@ -30,7 +30,11 @@ import { useShapeIsHover } from "@/core/hook/use-mouse-status";
 import { useCursor } from "@/core/hook/use-global-vars";
 import { mergeFuns, rangMod } from "@/utils/shared";
 import { Operate } from "../../html-mount/propertys/index.ts";
-import { useViewer } from "@/core/hook/use-viewer.ts";
+import {
+  useFixedScale,
+  useViewer,
+  useViewerInvertTransformConfig,
+} from "@/core/hook/use-viewer.ts";
 import { useMode } from "@/core/hook/use-status";
 import { Mode } from "@/constant/mode";
 
@@ -40,6 +44,7 @@ const props = defineProps<{
   id: string;
   color?: string;
   size?: number;
+  fixed?: boolean;
   disable?: boolean;
   drawIng?: boolean;
   opacity?: number;
@@ -55,11 +60,13 @@ const emit = defineEmits<{
 }>();
 
 const position = computed(() => props.points[props.ndx]);
-
+const scale = useFixedScale();
 const viewer = useViewer();
 const style = computed(() => {
   const color = getMouseColors(props.color || themeColor);
-  const size = props.size || 5;
+  let size = Math.max(props.size || 10, 10);
+  size = props.fixed ? scale.value * size : size;
+
   return {
     radius: size / 2,
     fill: props.drawIng || isHover.value || dragIng.value ? "#fff" : color.pub,

+ 4 - 2
src/core/components/share/edit-polygon.vue

@@ -4,7 +4,7 @@
       v-if="status.hover && canEdit && !operMode.mulSelection && data.points.length >= 2"
     >
       <EditLine
-        :data="data"
+        :data="{ ...data, fixed: fixed }"
         :points="data.points"
         :closed="closed"
         :id="data.id"
@@ -30,7 +30,8 @@
     <template v-if="(status.hover || status.active || addMode) && !operMode.mulSelection">
       <Point
         v-for="(_, ndx) in data.points"
-        :size="data.strokeWidth + 6"
+        :size="data.strokeWidth"
+        :fixed="fixed"
         :points="data.points"
         :ndx="ndx"
         :closed="closed"
@@ -65,6 +66,7 @@ const props = defineProps<{
   addMode?: boolean;
   canEdit?: boolean;
   closed?: boolean;
+  fixed?: boolean;
   shape: DC<EntityShape>;
 }>();
 const emit = defineEmits<{

+ 12 - 7
src/core/components/share/size-line.vue

@@ -36,20 +36,22 @@ import {
 import { flatPositions } from "@/utils/shared";
 import { useProportion } from "@/core/hook/use-proportion";
 import { TextPathConfig } from "konva/lib/shapes/TextPath";
+import { useFixedScale, useViewerInvertTransformConfig } from "@/core/hook/use-viewer";
 
 const props = withDefaults(
   defineProps<{
     points: Pos[];
     stroke?: string;
-    strokeWidth?: number;
     closed?: boolean;
     margin?: number;
+    fixed?: boolean;
   }>(),
   { stroke: "#999", strokeWidth: 1 }
 );
-
-const style = computed(() => ({ stroke: "#999", strokeWidth: 10 }));
-const fontSize = computed(() => 10 + style.value.strokeWidth * 2);
+const fscale = useFixedScale();
+const scale = computed(() => (props.fixed ? fscale.value : 1));
+const style = computed(() => ({ stroke: props.stroke, strokeWidth: 4 * scale.value }));
+const fontSize = computed(() => 10 * scale.value + style.value.strokeWidth * 2);
 const len = computed(() =>
   props.closed ? props.points.length : props.points.length - 1
 );
@@ -62,9 +64,12 @@ const isClockwise = computed(() => getPolygonDirection(props.points) <= 0);
 
 const proportion = useProportion();
 const getWidthText = (val: number) => Math.round(proportion.transform(val)).toString();
-const margin = computed(() =>
-  props.margin !== undefined ? props.margin! : -10 - style.value.strokeWidth * 2
-);
+const margin = computed(() => {
+  const selfMargin = style.value.strokeWidth * 2;
+  const margin = props.margin || 10 * scale.value;
+
+  return -(margin + selfMargin);
+});
 const lines = computed(() => {
   const lines: { points: Pos[][]; textConfig: TextPathConfig }[] = [];
   for (let i = 0; i < len.value; i++) {

+ 3 - 3
src/core/components/triangle/index.ts

@@ -12,12 +12,14 @@ export const defaultStyle = {
   stroke: '#000000',
   strokeWidth: 5,
   fontSize: 22,
+  fixed: true,
   align: "center",
   fontStyle: "normal",
   fontColor: '#000000',
 };
 
 export const addMode = "area";
+export const fixedStrokeOptions = [1, 2, 4];
 
 export const getMouseStyle = (data: TriangleData) => {
   const fillStatus = data.fill && getMouseColors(data.fill);
@@ -103,7 +105,5 @@ export const getPredefine = (key: keyof TriangleData) => {
 
   if (["fill", "stroke"].includes(key)) {
     return { canun: true };
-  } else if (key === "strokeWidth") {
-    return { proportion: true };
-  }
+  } 
 };

+ 12 - 1
src/core/components/triangle/temp-triangle.vue

@@ -40,12 +40,23 @@ import { Transform } from "konva/lib/Util";
 import { MathUtils } from "three";
 import { lineSpeed } from "@/utils/math.ts";
 import { useConfig } from "@/core/hook/use-config.ts";
+import { useFixedScale } from "@/core/hook/use-viewer.ts";
 const props = defineProps<{ data: TriangleData; addMode?: boolean; editer?: boolean }>();
 const emit = defineEmits<{
   (e: "updateContent", data: string): void;
   (e: "update:isEdit", data: boolean): void;
 }>();
-const data = computed(() => ({ ...defaultStyle, ...props.data }));
+const fscale = useFixedScale();
+const data = computed(() => {
+  const style = {
+    ...defaultStyle,
+    ...props.data,
+  };
+  if (style.fixed) {
+    style.strokeWidth *= fscale.value;
+  }
+  return style;
+});
 const config = useConfig();
 
 const shape = ref<DC<Line>>();

+ 4 - 1
src/core/components/triangle/triangle.vue

@@ -17,10 +17,12 @@
 </template>
 
 <script lang="ts" setup>
-import { TriangleData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
+import { TriangleData, fixedStrokeOptions, getMouseStyle, matResponse } from "./index.ts";
 import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import TempLine from "./temp-triangle.vue";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
+import { useInstallStrokeWidthDescribe } from "@/core/hook/use-describe.ts";
+import { watchEffect } from "vue";
 
 const props = defineProps<{ data: TriangleData }>();
 const emit = defineEmits<{
@@ -60,4 +62,5 @@ const { shape, tData, operateMenus, describes, data } = useComponentStatus({
     // "ref", "zIndex"
   ],
 });
+useInstallStrokeWidthDescribe(describes, data, fixedStrokeOptions);
 </script>

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

@@ -29,6 +29,7 @@ import { computed, onUnmounted } from "vue";
 import { components } from "../components";
 import { useComponentsAttach } from "../hook/use-component";
 import {
+  useFixedScale,
   useGetViewBoxPositionPixel,
   useViewerInvertTransformConfig,
   useViewerTransform,
@@ -169,7 +170,8 @@ const rectAxisSteps = computed(() => {
 
 const { transform } = useProportion();
 const getWidthText = (val: number) => Math.round(transform(val)).toString();
-const invConfig = useViewerInvertTransformConfig();
+
+const fscale = useFixedScale();
 const axissInfo = computed(() => {
   if (!rang.value) return;
   const infos: Record<string, { points: number[]; texts: TextConfig[] }> = {
@@ -203,7 +205,7 @@ const axissInfo = computed(() => {
 
       infos.left.texts.push({
         width: width,
-        text: getWidthText(width * invConfig.value.scaleY),
+        text: getWidthText(width * fscale.value),
         ...tf.decompose(),
       });
     }
@@ -233,7 +235,7 @@ const axissInfo = computed(() => {
 
       infos.right.texts.push({
         width: width,
-        text: getWidthText(width * invConfig.value.scaleY).toString(),
+        text: getWidthText(width * fscale.value).toString(),
         ...tf.decompose(),
       });
     }
@@ -256,7 +258,7 @@ const axissInfo = computed(() => {
       const width = cur - prev;
       infos.top.texts.push({
         width: width,
-        text: getWidthText(width * invConfig.value.scaleX).toString(),
+        text: getWidthText(width * fscale.value).toString(),
         ...lt,
       });
     }
@@ -279,7 +281,7 @@ const axissInfo = computed(() => {
       const width = cur - prev;
       infos.bottom.texts.push({
         width: width,
-        text: getWidthText(width * invConfig.value.scaleX).toString(),
+        text: getWidthText(width * fscale.value).toString(),
         ...lt,
       });
     }

+ 38 - 0
src/core/hook/use-describe.ts

@@ -0,0 +1,38 @@
+import { computed, Ref, watch } from "vue";
+import { PropertyDescribes } from "../html-mount/propertys";
+import {
+  getFixedStrokeWidthProperty,
+  sysDescribes,
+} from "../html-mount/propertys/describes";
+import { useStore } from "../store";
+import { Proportion } from "../store/store";
+
+export const useInstallStrokeWidthDescribe = (
+  describes: Ref<PropertyDescribes>,
+  shape: Ref<{ strokeWidth?: number; fixed?: boolean }>,
+  options = [1, 2, 4],
+  defProportion?: Proportion,
+  fixed = false
+) => {
+  const store = useStore();
+  const proportion = computed(() => {
+    return defProportion || { ...store.config.strokeProportion };
+  });
+
+  watch(
+    () => [fixed || shape.value.fixed, proportion.value] as const,
+    ([fixed, proportion]) => {
+      if (fixed) {
+        const property = getFixedStrokeWidthProperty(shape);
+        property.props.options = options.map((size) => ({
+          label: `${size} ${proportion.unit}`,
+          value: size / proportion.scale,
+        }));
+        describes.value.strokeWidth = property as PropertyDescribes[string];
+      } else {
+        describes.value.strokeWidth = sysDescribes.strokeWidth as any;
+      }
+    },
+    { immediate: true, flush: 'sync' }
+  );
+};

+ 1 - 0
src/core/hook/use-draw.ts

@@ -132,6 +132,7 @@ export const useInteractiveDrawShapeAPI = installGlobalVar(() => {
         operate: { single },
         callback: leave,
       };
+      console.log(interactiveProps.value)
       enter();
     },
     quitDrawShape: () => {

+ 9 - 0
src/core/hook/use-mouse-status.ts

@@ -33,9 +33,11 @@ const stageHoverMap = new WeakMap<
 >();
 export const getHoverShape = (stage: Stage) => {
   let isStop = false;
+  let interval: any
   const stop = () => {
     if (isStop || !stageHoverMap.has(stage)) return;
     isStop = true;
+    clearInterval(interval);
     const data = stageHoverMap.get(stage)!;
     if (--data.count <= 0) {
       data.des();
@@ -50,13 +52,20 @@ export const getHoverShape = (stage: Stage) => {
 
   const hover = ref<EntityShape>();
   const enterHandler = (ev: KonvaEventObject<any, Stage>) => {
+    clearInterval(interval)
     const target = ev.target;
     hover.value = target;
     target.off(`pointerleave`, leaveHandler);
     target.on(`pointerleave`, leaveHandler as any);
+    interval = setInterval(() => {
+      if (!stage.isAncestorOf(target)) {
+        leaveHandler()
+      }
+    }, 100)
   };
 
   const leaveHandler = (ev?: KonvaEventObject<any, Stage>) => {
+    clearInterval(interval)
     if (hover.value) {
       hover.value.off(`pointerleave`, leaveHandler);
       hover.value = undefined;

+ 5 - 7
src/core/hook/use-selection.ts

@@ -29,6 +29,7 @@ import {
 import { EntityShape } from "@/deconstruction";
 import { Util } from "konva/lib/Util";
 import {
+  useFixedScale,
   useViewerInvertTransform,
   useViewerInvertTransformConfig,
 } from "./use-viewer";
@@ -176,7 +177,7 @@ export const useShapesIcon = (
     ...args,
     listening: false,
   };
-  const invConfig = useViewerInvertTransformConfig();
+  const fScale = useFixedScale()
   const invMat = useViewerInvertTransform();
   const getShapeMat = (shape: EntityShape) => {
     const rect = shape.getClientRect();
@@ -200,13 +201,13 @@ export const useShapesIcon = (
         const mat = ref(getShapeMat(addShape));
         const data = reactive({ ...iconProps, mat: mat });
         const update = frameEebounce(() => {
-          data.width = invConfig.value.scaleX * iconProps.width;
-          data.height = invConfig.value.scaleY * iconProps.height;
+          data.width = fScale.value * iconProps.width;
+          data.height = fScale.value * iconProps.height;
           mat.value = getShapeMat(addShape);
         });
         const unHooks = [
           on(addShape, update),
-          watch(invConfig, update, { immediate: true, flush: "post" }),
+          watch(fScale, update, { immediate: true, flush: "post" }),
           mParts.add({
             comp: markRaw(Icon),
             props: { data },
@@ -243,7 +244,6 @@ export const useStoreSelectionManage = installGlobalVar((): SelectionManage => {
       return false;
     }
     const item = store.items.find((item) => item.id === id);
-    console.log(shape)
     return !!(item && !item.lock);
   };
   const listener = (shape: EntityShape) => {
@@ -296,8 +296,6 @@ export const useSelectionRevise = () => {
     selfSet = true;
     status.selects = shapes;
     selfSet = false;
-
-    console.log(shapes, shapes.map(item => store.getItemById(item.id())))
   };
 
   let initSelections: EntityShape[] = [];

+ 0 - 1
src/core/hook/use-transformer.ts

@@ -256,7 +256,6 @@ export const useShapeDrag = (shape: Ref<DC<EntityShape> | undefined>) => {
 
     let start: Pos | undefined;
     const enter = (position: Pos) => {
-      console.log('enter')
       mode.push(Mode.update);
       if (!start) {
         start = position;

+ 13 - 1
src/core/hook/use-viewer.ts

@@ -3,7 +3,7 @@ import { computed, nextTick, ref, watch, watchEffect } from "vue";
 import { dragListener, scaleListener } from "../../utils/event.ts";
 import { globalWatch, installGlobalVar, useStage } from "./use-global-vars.ts";
 import { useCan } from "./use-status";
-import { mergeFuns } from "../../utils/shared.ts";
+import { frameEebounce, mergeFuns } from "../../utils/shared.ts";
 import { Transform } from "konva/lib/Util";
 import { lineLen } from "@/utils/math.ts";
 import { useResize } from "./use-event.ts";
@@ -99,6 +99,18 @@ export const useViewerInvertTransformConfig = () => {
   return computed(() => transform.value.decompose());
 };
 
+export const useFixedScale = () => {
+  const inv = useViewerInvertTransformConfig()
+  const scale = ref(inv.value.scaleX)
+  watch(inv, frameEebounce((inv) => {
+    const newScale = inv.scaleX
+    // if (Math.abs(newScale - scale.value) > 0.05) {
+      scale.value = newScale
+    // }
+  }))
+  return scale
+}
+
 export const useUnitTransform = installGlobalVar(() => {
   const transform = useViewerTransform();
   const invTransform = useViewerInvertTransform();

+ 40 - 0
src/core/html-mount/propertys/describes.ts

@@ -0,0 +1,40 @@
+import { Ref } from "vue";
+import sysDescribes from "./sys-describes.json";
+
+export const getFixedStrokeWidthProperty = (self: Ref<{ strokeWidth?: number }>) => {
+  const property = {
+    type: "select",
+    label: "边框粗细",
+    props: {
+      options: [
+        {
+          label: "1px",
+          value: 1,
+        },
+        {
+          label: "2px",
+          value: 2,
+        },
+        {
+          label: "4px",
+          value: 4,
+        },
+      ],
+    },
+    "layout-type": "row",
+    get value() {
+      if (self.value.strokeWidth) {
+        return property.props.options.find(item => Math.abs(item.value - self.value.strokeWidth!) < 0.01)?.value;
+      } else {
+        return self.value.strokeWidth
+      }
+    },
+    set value(val) {
+      self.value.strokeWidth = val!
+    },
+  };
+
+  return property
+};
+
+export { sysDescribes };

+ 6 - 6
src/core/html-mount/propertys/index.ts

@@ -7,8 +7,8 @@ import InputNum from "./components/input-num.vue";
 import Proportion from "./components/proportion.vue";
 import Text from "./components/text.vue";
 import FixProportion from "./components/fix-proportion.vue";
-import originDescribes from "./describes.json";
-import { ref, Ref } from "vue";
+import { sysDescribes } from "./describes";
+import { Ref } from "vue";
 
 export const colorType = "color";
 export const selectType = "select";
@@ -18,7 +18,7 @@ export const proportionType = "proportion";
 export const fixProportionType = "fixProportion"
 export const textType = 'text'
 export const inputNumType = 'inputNum'
-export { originDescribes }
+export { sysDescribes }
 
 export const propertyComponents = {
   [colorType]: Color,
@@ -58,15 +58,15 @@ export type PropertysData<T extends PropertyDescribes = PropertyDescribes> = {
   [K in keyof T]: PropertyValue<T[K]["type"]>;
 };
 
-export type PropertyKey = keyof typeof originDescribes;
+export type PropertyKey = keyof typeof sysDescribes;
 export type PropertyKeys = PropertyKey[];
 
 export const mergeDescribes = (data: Ref<any>, defData: any, keys: PropertyKeys, describes: PropertyDescribes = {}) => {
   for (const key of keys) {
-    if (!originDescribes[key]) {
+    if (!sysDescribes[key]) {
       continue;
     }
-    ;(describes as any)[key] = { ...originDescribes[key] };
+    ;(describes as any)[key] = { ...sysDescribes[key] };
 
     if (!("value" in describes[key])) {
       Object.defineProperty(describes[key], "value", {

+ 1 - 0
src/core/html-mount/propertys/mount-describes.vue

@@ -64,6 +64,7 @@ const props = defineProps<{
   describes: PropertyDescribes;
   calDelete?: boolean;
 }>();
+
 const emit = defineEmits<{
   (e: "change"): void;
   (e: "delete"): void;

+ 0 - 1
src/core/html-mount/propertys/mount.vue

@@ -63,5 +63,4 @@ const hidden = computed(
       mode.value.has(Mode.draging))
 );
 
-watch(hidden, (hide) => !hide && console.log(props.data));
 </script>

src/core/html-mount/propertys/describes.json → src/core/html-mount/propertys/sys-describes.json


+ 44 - 44
src/core/store/store.ts

@@ -7,21 +7,24 @@ export const sortFn = (
   b: Pick<DrawItem, "zIndex" | "createTime">
 ) => a.zIndex - b.zIndex || a.createTime - b.createTime;
 
+export type Proportion = { scale: number; unit: string };
 export type StoreConfig = {
-  proportion: { scale: number, unit: string }
+  proportion: Proportion;
+  strokeProportion: Proportion;
   compass: {
     rotation: number;
     url: string;
   };
 };
 export type StoreData = {
-  layers: Record<string, DrawData>,
+  layers: Record<string, DrawData>;
   config: StoreConfig;
   __currentLayer: string;
 };
 const defConfig: StoreData["config"] = {
-  compass: { rotation: 0, url: 'icons/edit_compass.svg' },
-  proportion: {scale: 10, unit: 'mm'}
+  compass: { rotation: 0, url: "icons/edit_compass.svg" },
+  proportion: { scale: 1, unit: "px" },
+  strokeProportion: { scale: 1, unit: "px" }
 };
 
 export const getEmptyStoreData = (): StoreData => {
@@ -36,22 +39,22 @@ export const useStoreRaw = defineStore("draw-data", {
   state: () => ({ data: getEmptyStoreData() }),
   getters: {
     currentLayer() {
-      const layer = (this as any).data.__currentLayer
-      const layers = (this as any).layers
+      const layer = (this as any).data.__currentLayer;
+      const layers = (this as any).layers;
       if (layers.includes(layer)) {
-        return layer
+        return layer;
       } else {
-        return layers[0] 
+        return layers[0];
       }
     },
     layers() {
-      const data = this.data as StoreData
-      return Object.keys(data.layers)
+      const data = this.data as StoreData;
+      return Object.keys(data.layers);
     },
     typeItems() {
-      const data = this.data as StoreData
-      const layer = (this as any).currentLayer
-      return data.layers[layer] || {}
+      const data = this.data as StoreData;
+      const layer = (this as any).currentLayer;
+      return data.layers[layer] || {};
     },
     items() {
       return Object.values(this.typeItems).flat() as DrawItem[];
@@ -65,26 +68,26 @@ export const useStoreRaw = defineStore("draw-data", {
   },
   actions: {
     setStore(store: Partial<StoreData>) {
-      const newStore = JSON.parse(JSON.stringify(store)) ;
+      const newStore = JSON.parse(JSON.stringify(store));
       this.$patch((state) => {
         state.data = {
           ...state.data,
           ...newStore,
           config: {
             ...state.data.config,
-            ...(newStore.config || {})
-          }
+            ...(newStore.config || {}),
+          },
         };
       });
     },
     setLayerStore(layerStore: DrawData) {
-      this.$patch(state => {
-        state.data.layers[this.currentLayer] = layerStore
-      })
+      this.$patch((state) => {
+        state.data.layers[this.currentLayer] = layerStore;
+      });
     },
     getItemNdx<T extends ShapeType>(type: T, id: string) {
       const items = this.typeItems[type];
-      
+
       if (items) {
         return items.findIndex((item) => item.id === id);
       }
@@ -101,7 +104,7 @@ export const useStoreRaw = defineStore("draw-data", {
       items.forEach((item) => this.addItem(type, item));
     },
     addItem<T extends ShapeType>(type: T, item: DrawItem<T>) {
-      const typeItems = this.typeItems
+      const typeItems = this.typeItems;
       this.$patch(() => {
         if (!(type in typeItems)) {
           typeItems[type] = [];
@@ -111,7 +114,7 @@ export const useStoreRaw = defineStore("draw-data", {
     },
     delItem<T extends ShapeType>(type: T, id: string) {
       const ndx = this.getItemNdx(type, id);
-      const typeItems = this.typeItems
+      const typeItems = this.typeItems;
       if (~ndx) {
         this.$patch(() => {
           typeItems[type]!.splice(ndx, 1);
@@ -122,14 +125,14 @@ export const useStoreRaw = defineStore("draw-data", {
       type: T,
       playData: { value: Partial<DrawItem<T>>; id: string }
     ) {
-      const typeItems = this.typeItems
+      const typeItems = this.typeItems;
       const ndx = this.getItemNdx(type, playData.id);
       if (~ndx) {
         this.$patch(() => {
-          console.log()
-          const old = typeItems[type]![ndx]
+          console.log();
+          const old = typeItems[type]![ndx];
           Object.assign(typeItems[type]![ndx], playData.value);
-          const newv = typeItems[type]![ndx]
+          const newv = typeItems[type]![ndx];
         });
       }
     },
@@ -141,8 +144,8 @@ export const useStoreRaw = defineStore("draw-data", {
       }
     },
     getType(id: string) {
-      const typeItems = this.typeItems
-      const types = (Object.keys(typeItems)) as ShapeType[];
+      const typeItems = this.typeItems;
+      const types = Object.keys(typeItems) as ShapeType[];
       for (const type of types) {
         if (typeItems[type]?.some((item) => item.id === id)) {
           return type;
@@ -162,25 +165,25 @@ export const useStoreRaw = defineStore("draw-data", {
       this.$patch((state) => {
         state.data.config = {
           ...state.data.config,
-          ...config
+          ...config,
         };
       });
     },
     setCurrentLayer(layer: string) {
       if (!this.layers.includes(layer)) {
-        throw `不存在${layer}层`
+        throw `不存在${layer}层`;
       } else {
-        this.data.__currentLayer = layer
+        this.data.__currentLayer = layer;
       }
     },
     clear() {
-      this.data.layers[this.currentLayer] = {}
+      this.data.layers[this.currentLayer] = {};
     },
     addLayer(layer: string) {
       if (this.layers.includes(layer)) {
-        throw `已存在${layer}层`
+        throw `已存在${layer}层`;
       } else {
-        this.data.layers[layer] = {}
+        this.data.layers[layer] = {};
       }
     },
     delLayer(layer: string, translateLayer?: string) {
@@ -190,23 +193,20 @@ export const useStoreRaw = defineStore("draw-data", {
 
       if (translateLayer) {
         if (!this.layers.includes(translateLayer)) {
-          throw `不存在${translateLayer}层`
+          throw `不存在${translateLayer}层`;
         }
-        const layerData = this.data.layers[layer]  
-        const tLayerData = this.data.layers[translateLayer]
-        const keys = Object.keys(layerData) as ShapeType[]
+        const layerData = this.data.layers[layer];
+        const tLayerData = this.data.layers[translateLayer];
+        const keys = Object.keys(layerData) as ShapeType[];
 
         for (const key of keys) {
           if (key in tLayerData && tLayerData[key]) {
-            tLayerData[key] = [
-              ...tLayerData[key],
-              ...layerData[key]!
-            ] as any
+            tLayerData[key] = [...tLayerData[key], ...layerData[key]!] as any;
           } else {
-            tLayerData[key] = layerData[key] as any
+            tLayerData[key] = layerData[key] as any;
           }
         }
       }
-    }
+    },
   },
 });

+ 7 - 5
src/core/viewer.ts

@@ -93,14 +93,16 @@ export class Viewer {
 
   scale(center: Pos, scale: number, initMat = this.viewMat) {
     const base = initMat.decompose().scaleX;
-    const isMin = base * scale < 0.05
-    const isMax = base * scale > 50
+    const min = 0.005
+    const max = 50
+    const isMin = base * scale < min
+    const isMax = base * scale > max
     if (isMax || isMin) {
-      console.error("缩放范围0.05~50 将自动调整缩放值");
+      console.error(`缩放范围${min}~${max} 将自动调整缩放值`);
       if (scale > 1 && isMin) {
-        scale = 0.05 / base
+        scale = min / base
       } else if (scale < 1 && isMax) {
-        scale = 50 / base
+        scale = max / base
       } else {
         return;
       }

+ 46 - 4
src/example/components/slide/actions.ts

@@ -1,7 +1,11 @@
 import { DrawItem, shapeNames, ShapeType } from "@/index";
 import { defaultStyle } from "@/core/components/image/index";
 import { v4 as uuid } from "uuid";
-import { getMapInfo, SelectMapImageProps } from "../../dialog/basemap/index";
+import {
+  getMapInfo,
+  SelectMapImageProps,
+  TileGroup,
+} from "../../dialog/basemap/index";
 import { selectAI } from "../../dialog/ai";
 import { drawPlatformResource } from "../../platform/platform-draw";
 import { selectFile } from "@/utils/dom";
@@ -10,11 +14,12 @@ import { Draw } from "../container/use-draw";
 import { MenuItem } from "./menu";
 import { copy } from "@/utils/shared";
 import { ElMessage } from "element-plus";
-import { getRealPixel } from "@/example/fuse/views/tabulation/gen-tab";
 import { nextTick, ref } from "vue";
 import { Rect } from "konva/lib/shapes/Rect";
 import { Size } from "@/utils/math";
 import { getBaseItem } from "@/core/components/util";
+import { loading } from "@/example/loadding";
+import { overviewMMToPixel } from "@/example/constant";
 
 export type PresetAdd<T extends ShapeType = ShapeType> = {
   type: T;
@@ -36,7 +41,7 @@ export const draw: MenuItem = {
   value: uuid(),
   defSelect: true,
   children: [
-    // { icon: "line", ...genDrawItem('sequentLine') },
+    { icon: "line", ...genDrawItem('lineChunk') },
     { icon: "line", ...genDrawItem("line") },
     { icon: "arrows", ...genDrawItem("arrow"), single: true },
     { icon: "rectangle", ...genDrawItem("rectangle"), single: true },
@@ -80,6 +85,40 @@ export const imp: MenuItem = {
     },
     {
       value: uuid(),
+      icon: "map",
+      name: "地图",
+      handler: async (draw: Draw) => {
+        const tileGroups = (await loading(
+          window.platform.getTileGroups()
+        )) as TileGroup[];
+        const result = await selectMap({
+          search: window.platform.searchAddress,
+          activeGroupIndex: 0,
+          tileGroups,
+        });
+        const realSize = result.info.size;
+        const scale = 1000 * overviewMMToPixel;
+
+
+        ElMessage.warning("请在画图面板中选择放置位置,鼠标右键取消");
+        draw.enterDrawShape(
+          "image",
+          {
+            width: realSize.width * scale,
+            height: realSize.height * scale,
+            url: result.url,
+            key: "kankan-floor-cover",
+            lock: true,
+            cornerRadius: 0,
+            zIndex: -2,
+          },
+          true
+        );
+        // emit("updateMapImage", { url: result.url, size: result.info.size });
+      },
+    },
+    {
+      value: uuid(),
       icon: "local_i",
       name: "本地",
       handler: async (draw: Draw) => {
@@ -105,7 +144,11 @@ export const imp: MenuItem = {
           {
             width: image.width,
             height: image.height,
+            key: "kankan-floor-cover",
             url,
+            lock: true,
+            cornerRadius: 0,
+            zIndex: -2,
           },
           true
         );
@@ -118,7 +161,6 @@ export const getPaperConfig = (p: number[], scale: number) => {
   const pad = 5 * scale;
   const size = { width: p[0] * scale, height: p[1] * scale };
   const margin = [pad, pad, pad, pad * 5];
-  const a = getRealPixel(5, "a4");
   return { size, margin };
 };
 export const paperConfigs = {

+ 5 - 1
src/example/constant.ts

@@ -255,4 +255,8 @@ export const tableTitleKey = "__tableTitleKey";
 export const tableCompassKey = "__tableCompassKey";
 export const mapImageKey = "__mapKey";
 export const tableCoverWidth = 370;
-export const tableCoverHeight = 306;
+export const tableCoverHeight = 306;
+
+// 像素转毫米比例
+export const overviewMMToPixel = 0.1
+export const overviewBorderMMToPixel = 7.69

+ 8 - 4
src/example/dialog/basemap/leaflet/index.vue

@@ -166,13 +166,17 @@ const submit = async (): Promise<BasemapInfo> => {
   const bound = lMap.value.getBounds();
   const southWest = bound.getSouthWest(); // 西南角
   const northEast = bound.getNorthEast(); // 东北角
+
+  // 修正:计算宽度应该使用相同的纬度
   const width = lMap.value.distance(
-    [southWest.lng, northEast.lat],
-    [northEast.lng, northEast.lat]
+    [southWest.lat, southWest.lng], // 西南角
+    [southWest.lat, northEast.lng] // 同纬度,经度不同
   );
+
+  // 修正:计算高度应该使用相同的经度
   const height = lMap.value.distance(
-    [northEast.lng, southWest.lat],
-    [northEast.lng, northEast.lat]
+    [southWest.lat, southWest.lng], // 西南角
+    [northEast.lat, southWest.lng] // 同经度,纬度不同
   );
 
   let blob: Blob;

+ 37 - 24
src/example/fuse/views/defStyle.ts

@@ -1,10 +1,20 @@
 import { defaultStyle as iconDefStyle } from "@/core/components/icon";
+import { fixedStrokeOptions as iconFixedStrokeOptions } from "@/core/components/icon";
 import { defaultStyle as lineIconDefStyle } from "@/core/components/line-icon";
+import { fixedStrokeOptions as lineIconFixedStrokeOptions } from "@/core/components/line-icon";
 import { defaultStyle as rectDefStyle } from "@/core/components/rectangle";
+import { fixedStrokeOptions as rectFixedStrokeOptions } from "@/core/components/rectangle";
 import { defaultStyle as circleDefStyle } from "@/core/components/circle";
+import { fixedStrokeOptions as circleFixedStrokeOptions } from "@/core/components/circle";
 import { defaultStyle as triangleDefStyle } from "@/core/components/triangle";
+import { fixedStrokeOptions as triangleFixedStrokeOptions } from "@/core/components/triangle";
 import { defaultStyle as polygonDefStyle } from "@/core/components/polygon";
+import { fixedStrokeOptions as polygonFixedStrokeOptions } from "@/core/components/polygon";
 import { defaultStyle as arrowDefStyle } from "@/core/components/arrow";
+import { fixedStrokeOptions as arrowFixedStrokeOptions } from "@/core/components/arrow";
+import { defaultStyle as lineDefStyle } from "@/core/components/line";
+import { defaultStyle as lineChunkDefStyle } from "@/core/components/line-chunk";
+import { fixedStrokeOptions as lineChunkFixedStrokeOptions } from "@/core/components/line-chunk";
 import {
   defaultStyle as serialDefStyle,
   defaultTableStyle as serialTableDefStyle,
@@ -17,7 +27,7 @@ import { getRealPixel } from "./tabulation/gen-tab";
 import { Draw } from "@/example/components/container/use-draw";
 import { ShapeType } from "@/index";
 import { watch } from "vue";
-import { PropertyDescribes } from "@/core/html-mount/propertys";
+import { overviewBorderMMToPixel, overviewMMToPixel } from "@/example/constant";
 
 const setDefStyle = <T extends {}>(
   sys: T,
@@ -116,31 +126,34 @@ export const tabCustomStyle = (p: PaperKey, draw: Draw) => {
   return mergeFuns(backs);
 };
 
+const getOverviewRealPixel = (real: number, border = false) =>
+  real * (border ? overviewBorderMMToPixel : overviewMMToPixel);
+
 export const overviewCustomStyle = (draw: Draw) => {
-  const filterIcon = (data: PropertyDescribes) => {
-    data.strokeWidth.props = {
-      ...data.strokeWidth.props,
-      proportion: true,
-    };
-    return data;
-  };
+  const realFixedStrokeOptions = [0.13, 0.18, 0.25, 0.35, 0.5, 0.7];
+  const defFixelStroke = getOverviewRealPixel(realFixedStrokeOptions[0], true);
   const backs = [
-    draw.mountFilter.setMenusFilter("icon", filterIcon),
-    draw.mountFilter.setMenusFilter("lineIcon", filterIcon),
-    setDefStyle(
-      iconDefStyle,
-      {
-        strokeWidth: 1,
-      } as any,
-      "icon"
-    ),
-    setDefStyle(
-      lineIconDefStyle,
-      {
-        strokeWidth: 1,
-      } as any,
-      "icon"
-    ),
+    setDefStyle(lineDefStyle, { strokeWidth: getOverviewRealPixel(120) }),
+    setDefStyle(triangleFixedStrokeOptions, realFixedStrokeOptions),
+    setDefStyle(circleFixedStrokeOptions, realFixedStrokeOptions),
+    setDefStyle(arrowFixedStrokeOptions, realFixedStrokeOptions),
+    setDefStyle(rectFixedStrokeOptions, realFixedStrokeOptions),
+    setDefStyle(polygonFixedStrokeOptions, realFixedStrokeOptions),
+    setDefStyle(iconFixedStrokeOptions, realFixedStrokeOptions),
+    setDefStyle(lineIconFixedStrokeOptions, realFixedStrokeOptions),
+    setDefStyle(lineChunkFixedStrokeOptions, realFixedStrokeOptions),
+    
+
+    setDefStyle(lineChunkDefStyle, { strokeWidth: defFixelStroke }),
+    setDefStyle(lineIconDefStyle, { strokeWidth: defFixelStroke }),
+    setDefStyle(iconDefStyle, { strokeWidth: defFixelStroke }),
+    setDefStyle(polygonDefStyle, { strokeWidth: defFixelStroke }),
+    setDefStyle(triangleDefStyle, { strokeWidth: defFixelStroke }),
+    setDefStyle(circleDefStyle, { strokeWidth: defFixelStroke }),
+    setDefStyle(arrowDefStyle, { strokeWidth: defFixelStroke }),
+    setDefStyle(rectDefStyle, { strokeWidth: defFixelStroke }),
+    setDefStyle(iconDefStyle, { strokeWidth: 1 } as any, "icon"),
+    setDefStyle(lineIconDefStyle, { strokeWidth: 1 } as any, "icon"),
   ];
   return mergeFuns(backs);
 };

+ 8 - 12
src/example/fuse/views/overview/index.vue

@@ -1,16 +1,8 @@
 <template>
-  <Container
-    :upload-resourse="uploadResourse"
-    v-model:full="full"
-    :ref="(d: any) => (draw = d?.draw)"
-  >
+  <Container :upload-resourse="uploadResourse" v-model:full="full" :ref="(d: any) => (draw = d?.draw)">
     <template #header>
-      <Header
-        @selectVR="(scene) => (vrScene = scene)"
-        title="绘图"
-        @save-after="() => mergeFuns(saveAfterHandlers)()"
-        :ref="(r) => (header = r)"
-      />
+      <Header @selectVR="(scene) => (vrScene = scene)" title="绘图" @save-after="() => mergeFuns(saveAfterHandlers)()"
+        :ref="(r) => (header = r)" />
     </template>
     <template #slide>
       <Slide />
@@ -42,6 +34,7 @@ import { params, preventReload } from "@/example/env";
 import { getFloors } from "@/example/platform/resource-swkk";
 import { mergeFuns } from "@/utils/shared";
 import { drawPlatformResource } from "@/example/platform/platform-draw";
+import { overviewBorderMMToPixel, overviewMMToPixel } from "@/example/constant";
 
 const uploadResourse = window.platform.uploadResourse;
 const full = ref(false);
@@ -93,7 +86,10 @@ const init = async (draw: Draw) => {
   draw.config.showLabelLine = true;
   draw.config.showComponentSize = false;
   draw.config.back = { color: "#f0f2f5", opacity: 1 };
-  draw.store.setConfig({ proportion: { scale: 10, unit: "mm" } });
+  draw.store.setConfig({
+    proportion: { scale: 1 / overviewMMToPixel, unit: "mm" },
+    strokeProportion: { scale: 1 / overviewBorderMMToPixel, unit: "mm" },
+  });
   // setMap(draw);
   draw.store.setStore(overviewData.value.store);
   overviewData.value.viewport && draw.viewer.setViewMat(overviewData.value.viewport);

+ 2 - 2
src/example/platform/platform-draw.ts

@@ -22,6 +22,7 @@ import {
   LineIconData,
 } from "@/core/components/line-icon";
 import { RectangleData } from "@/core/components/rectangle";
+import { overviewMMToPixel } from "../constant";
 
 const getSizePlaceBoxImage = ({ width, height }: Size) => {
   const borderWidth = 10;
@@ -427,11 +428,10 @@ export const drawPlatformResource = async (
   draw: Draw
 ) => {
   // 默认为米,转为厘米
-  const resource = await getResource({ ...sceneData, scale: 100 });
+  const resource = await getResource({ ...sceneData, scale: 1000 * overviewMMToPixel });
   let bound = null as ReturnType<ReturnType<typeof genBound>["get"]>;
 
   await draw.history.onceTrack(async () => {
-    draw.store.setConfig({ proportion: { scale: 10, unit: "mm" } });
     bound = await drawSceneResource(resource, draw);
     if (typeof resource.compass === "number") {
       draw.store.setConfig({