Parcourir la source

feat: 提供多图层分组

bill il y a 4 mois
Parent
commit
1f66908047
36 fichiers modifiés avec 1398 ajouts et 1036 suppressions
  1. 1 0
      public/icons/grouping.svg
  2. 4 3
      src/constant/index.ts
  3. 1 1
      src/core/components/arrow/arrow.vue
  4. 1 1
      src/core/components/circle/circle.vue
  5. 1 1
      src/core/components/group/group.vue
  6. 2 2
      src/core/components/icon/icon.vue
  7. 1 1
      src/core/components/image/image.vue
  8. 1 1
      src/core/components/line/line.vue
  9. 1 1
      src/core/components/polygon/polygon.vue
  10. 1 1
      src/core/components/rectangle/rectangle.vue
  11. 1 1
      src/core/components/serial/serial.vue
  12. 1 1
      src/core/components/table/table.vue
  13. 1 1
      src/core/components/text/text.vue
  14. 1 1
      src/core/components/triangle/triangle.vue
  15. 3 0
      src/core/components/util.ts
  16. 13 6
      src/core/helper/compass.vue
  17. 87 0
      src/core/helper/layers.vue
  18. 1 1
      src/core/hook/use-component.ts
  19. 2 2
      src/core/hook/use-history.ts
  20. 1 1
      src/core/hook/use-mouse-status.ts
  21. 6 5
      src/core/hook/use-selection.ts
  22. 162 0
      src/core/html-mount/hover-triggle.vue
  23. 0 0
      src/core/html-mount/propertys/components/checkbox.vue
  24. 0 0
      src/core/html-mount/propertys/components/color.vue
  25. 0 0
      src/core/html-mount/propertys/components/num.vue
  26. 0 0
      src/core/html-mount/propertys/components/proportion.vue
  27. 0 0
      src/core/html-mount/propertys/components/select.vue
  28. 0 0
      src/core/html-mount/propertys/describes.json
  29. 4 4
      src/core/propertys/hover-operate.vue
  30. 0 0
      src/core/html-mount/propertys/index.ts
  31. 3 3
      src/core/propertys/mount.vue
  32. 9 1
      src/core/renderer/renderer.vue
  33. 22 7
      src/core/store/index.ts
  34. 99 27
      src/core/store/store.ts
  35. 1 1
      src/example/fuse/views/home.vue
  36. 967 962
      src/example/fuse/views/test.ts

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
public/icons/grouping.svg


+ 4 - 3
src/constant/index.ts

@@ -1,5 +1,6 @@
-export const DomMountId =  'dom-mount'
-export const DomOutMountId =  'dom-out-mount'
+export const DomMountId = 'dom-mount'
+export const DomOutMountId = 'dom-out-mount'
 export const DataGroupId = 'data-group'
 export const rendererMap = new WeakMap<any, { unmounteds: (() => void)[] }>()
-export const rendererName = 'draw-renderer'
+export const rendererName = 'draw-renderer'
+export const defaultLayer = 'default'

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

@@ -17,7 +17,7 @@
 </template>
 
 <script lang="ts" setup>
-import { PropertyUpdate, Operate } from "../../propertys";
+import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import { ArrowData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
 import { TempComponent } from "./";
 import { useComponentStatus } from "@/core/hook/use-component.ts";

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

@@ -17,7 +17,7 @@
 
 <script lang="ts" setup>
 import { CircleData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
-import { PropertyUpdate, Operate } from "../../propertys";
+import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import TempCircle from "./temp-circle.vue";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
 import { Transform } from "konva/lib/Util";

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

@@ -11,7 +11,7 @@
 
 <script lang="ts" setup>
 import TempGroup from "./temp-group.vue";
-import { Operate } from "../../propertys";
+import { Operate } from "../../html-mount/propertys/index.ts";
 import { GroupData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
 import { useMouseShapeStatus } from "@/core/hook/use-mouse-status.ts";

+ 2 - 2
src/core/components/icon/icon.vue

@@ -13,9 +13,9 @@
 import TempIcon from "./temp-icon.vue";
 import { IconData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
-import { PropertyUpdate, Operate, mergeDescribes } from "../../propertys";
+import { PropertyUpdate, Operate, mergeDescribes } from "../../html-mount/propertys/index.ts";
 import { Transform } from "konva/lib/Util";
-import originDescribes from "../../propertys/describes.json";
+import originDescribes from "../../html-mount/propertys/describes.json";
 import { ref } from "vue";
 import { MathUtils } from "three";
 

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

@@ -13,7 +13,7 @@
 import TempImage from "./temp-image.vue";
 import { ImageData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
-import { PropertyUpdate, Operate } from "../../propertys";
+import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 
 const props = defineProps<{ data: ImageData }>();
 const emit = defineEmits<{

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

@@ -19,7 +19,7 @@
 <script lang="ts" setup>
 import { LineData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
-import { PropertyUpdate, Operate } from "../../propertys";
+import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import TempLine from "./temp-line.vue";
 import { EditPen } from "@element-plus/icons-vue";
 import { useInteractiveDrawShapeAPI } from "@/core/hook/use-draw.ts";

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

@@ -19,7 +19,7 @@
 <script lang="ts" setup>
 import { PolygonData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
-import { PropertyUpdate, Operate } from "../../propertys/index.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";

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

@@ -16,7 +16,7 @@
 
 <script lang="ts" setup>
 import { RectangleData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
-import { PropertyUpdate, Operate } from "../../propertys";
+import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import TempLine from "./temp-rectangle.vue";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
 

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

@@ -16,7 +16,7 @@
 
 <script lang="ts" setup>
 import { SerialData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
-import { PropertyUpdate, Operate } from "../../propertys/index.ts";
+import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import { TempComponent } from "./";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
 import { Transform } from "konva/lib/Util";

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

@@ -29,7 +29,7 @@ import {
   TableCollData,
   matResponse,
 } from "./index.ts";
-import { PropertyUpdate, Operate } from "../../propertys";
+import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
 import { Transform } from "konva/lib/Util";
 import { MathUtils } from "three";

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

@@ -23,7 +23,7 @@ import {
   getWidth,
   getMinWidth,
 } from "./index.ts";
-import { PropertyUpdate, Operate } from "../../propertys";
+import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import TempText from "./temp-text.vue";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
 import { cloneRepShape, useCustomTransformer } from "@/core/hook/use-transformer.ts";

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

@@ -17,7 +17,7 @@
 
 <script lang="ts" setup>
 import { TriangleData, getMouseStyle, defaultStyle, matResponse } from "./index.ts";
-import { PropertyUpdate, Operate } from "../../propertys";
+import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
 import TempLine from "./temp-triangle.vue";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
 

+ 3 - 0
src/core/components/util.ts

@@ -2,6 +2,7 @@ import { lineVector, Pos, vectorAngle, verticalVector } from "@/utils/math";
 import { onlyId, rangMod } from "@/utils/shared";
 import { MathUtils } from "three";
 import { ComponentSnapInfo } from ".";
+import { defaultLayer } from "@/constant";
 
 export type BaseItem = {
   id: string;
@@ -10,6 +11,7 @@ export type BaseItem = {
   lock: boolean,
   opacity: number
   key?: string
+  layer: string
   ref: boolean
   listening?: boolean
 };
@@ -19,6 +21,7 @@ export const getBaseItem = (): BaseItem => ({
   createTime: Date.now(),
   lock: false,
   zIndex: 0,
+  layer: defaultLayer,
   opacity: 1,
   ref: false
 });

+ 13 - 6
src/core/helper/compass.vue

@@ -1,5 +1,8 @@
 <template>
-  <TempIcon :data="{ ...data, ...style, mat }" :ref="(e: any) => shape = e?.shape" />
+  <TempIcon
+    :data="({ ...data, ...style, mat } as any)"
+    :ref="(e: any) => shape = e?.shape"
+  />
   <PropertyUpdate
     :describes="describes"
     :data="data"
@@ -10,7 +13,7 @@
 
 <script lang="ts" setup>
 import TempIcon from "../components/icon/temp-icon.vue";
-import { PropertyUpdate, mergeDescribes } from "../propertys";
+import { PropertyUpdate, mergeDescribes } from "../html-mount/propertys/index.ts";
 import { computed, ref, watch } from "vue";
 import { themeMouseColors } from "@/constant/help-style.ts";
 import { getMouseColors } from "@/utils/colors.ts";
@@ -22,6 +25,7 @@ import { Transform } from "konva/lib/Util";
 import { getFixPosition } from "@/utils/bound.ts";
 import { useResize } from "../hook/use-event.ts";
 import { MathUtils } from "three";
+import { useViewerTransformConfig } from "../hook/use-viewer.ts";
 
 const config = useConfig();
 const data = ref({
@@ -55,7 +59,7 @@ const [style] = useAnimationMouseStyle({
       press: { coverFill: fillStatus.press },
     };
   },
-}) as any;
+} as any);
 
 const other = ref({ rotate: config.compass!.rotation });
 watch(
@@ -81,13 +85,16 @@ describes.rotate = {
 };
 
 const size = useResize();
+const viewerConfig = useViewerTransformConfig();
 const mat = computed(() => {
-  if (!size.value) return;
-
   const tf = new Transform();
+  if (!size.value) return tf.m;
+
   const pos = getFixPosition({ right: 20, top: 20 }, data.value, size.value);
   pos.x += data.value.width / 2;
   pos.y += data.value.height / 2;
-  return tf.translate(pos.x, pos.y).rotate(MathUtils.degToRad(other.value.rotate)).m;
+  return tf
+    .translate(pos.x, pos.y)
+    .rotate(MathUtils.degToRad(other.value.rotate + viewerConfig.value.rotation)).m;
 });
 </script>

+ 87 - 0
src/core/helper/layers.vue

@@ -0,0 +1,87 @@
+<template>
+  <TempIcon
+    :data="({ ...data, ...style, mat } as any)"
+    :ref="(e: any) => shape = e?.shape"
+  />
+  <HoverTriggle :target="shape">
+    <ElMenu class="menu-layout">
+      <ElMenuItem v-for="layer in store.layers" @click="store.setCurrentLayer(layer)">
+        <span>{{ layer }}</span>
+      </ElMenuItem>
+    </ElMenu>
+  </HoverTriggle>
+</template>
+
+<script lang="ts" setup>
+import TempIcon from "../components/icon/temp-icon.vue";
+import HoverTriggle from "../html-mount/hover-triggle.vue";
+import { computed, ref } from "vue";
+import { themeMouseColors } from "@/constant/help-style.ts";
+import { getMouseColors } from "@/utils/colors.ts";
+import { useAnimationMouseStyle } from "../hook/use-mouse-status.ts";
+import { Group } from "konva/lib/Group";
+import { DC } from "@/deconstruction.js";
+import { Transform } from "konva/lib/Util";
+import { ElMenu, ElMenuItem } from "element-plus";
+import { getFixPosition } from "@/utils/bound.ts";
+import { useResize } from "../hook/use-event.ts";
+import { useStore } from "../store/index.ts";
+
+const data = ref({
+  coverFill: "#000",
+  coverOpcatiy: 0,
+  strokeScaleEnabled: false,
+  width: 20,
+  height: 20,
+  rotation: 0,
+  // stroke: themeMouseColors.pub,
+  fill: themeMouseColors.pub,
+  url: "/icons/grouping.svg",
+});
+const shape = ref<DC<Group>>();
+const [style] = useAnimationMouseStyle({
+  data: data as any,
+  shape,
+  getMouseStyle: () => {
+    const fillStatus = getMouseColors(data.value.fill);
+    return {
+      default: {
+        fill: fillStatus.pub,
+      },
+      hover: { fill: fillStatus.hover },
+      press: { fill: fillStatus.press },
+    };
+  },
+} as any);
+
+const size = useResize();
+const mat = computed(() => {
+  const tf = new Transform();
+  if (!size.value) return tf.m;
+
+  const pos = getFixPosition({ left: 20, bottom: 20 }, data.value, size.value);
+  pos.x += data.value.width / 2;
+  pos.y += data.value.height / 2;
+  return tf.translate(pos.x, pos.y).m;
+});
+
+const store = useStore();
+</script>
+
+<style lang="scss" scoped>
+.menu-layout {
+  --el-menu-base-level-padding: 16px;
+  --el-menu-item-height: 32px;
+  --el-menu-item-font-size: 14px;
+
+  .el-menu-item {
+    align-items: center;
+    padding: 5px 16px 5px 6px !important;
+    color: var(--el-text-color-regular);
+  }
+  .el-menu-item [class^="el-icon"] {
+    margin: 0;
+    font-size: 1em;
+  }
+}
+</style>

+ 1 - 1
src/core/hook/use-component.ts

@@ -37,7 +37,7 @@ import {
 import { asyncTimeout, copy, mergeFuns, onlyId } from "@/utils/shared";
 import { Shape } from "konva/lib/Shape";
 import { Transform } from "konva/lib/Util";
-import { mergeDescribes, PropertyKeys } from "../propertys";
+import { mergeDescribes, PropertyKeys } from "../html-mount/propertys";
 import { useStore } from "../store";
 import { globalWatch, useStage } from "./use-global-vars";
 import { useAlignmentShape } from "./use-alignment";

+ 2 - 2
src/core/hook/use-history.ts

@@ -29,7 +29,7 @@ export class DrawHistory {
   bus = mitt<{
     attachs: Record<string, any>;
     renderer: void;
-    push: void;
+    push: string;
     pushed: void;
     redo: void;
     undo: void;
@@ -145,7 +145,7 @@ export class DrawHistory {
     if (this.onceFlag) {
       this.onceHistory = data;
     } else if (data !== this.current?.data) {
-      this.bus.emit("push");
+      this.bus.emit("push", data);
       this.history.push({ attachs: JSON.stringify(this.pushAttachs), data });
       this.pushAttachs = {};
       this.bus.emit("pushed");

+ 1 - 1
src/core/hook/use-mouse-status.ts

@@ -418,5 +418,5 @@ export const useAnimationMouseStyle = <T extends ShapeType>(
       status.value.resume();
       resumeAnimation();
     },
-  ];
+  ] as const;
 };

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

@@ -40,16 +40,16 @@ const normalSelectIds = (
   ids: string[],
   needChildren = false
 ) => {
-  if (!store.data.typeItems.group) return ids;
+  if (!store.typeItems.group) return ids;
 
-  const gChildrenIds = store.data.typeItems.group.map((item) => item.ids);
+  const gChildrenIds = store.typeItems.group.map((item) => item.ids);
   const findNdx = (id: string) =>
     gChildrenIds.findIndex((cIds) => cIds.includes(id));
   if (!needChildren) {
     return ids.filter((id) => !~findNdx(id));
   }
 
-  const groupIds = store.data.typeItems.group.map((item) => item.id);
+  const groupIds = store.typeItems.group.map((item) => item.id);
   const nIds: string[] = [];
   for (let i = 0; i < ids.length; i++) {
     let ndx = findNdx(ids[i]);
@@ -60,7 +60,7 @@ const normalSelectIds = (
       continue;
     }
 
-    const group = store.data.typeItems.group[ndx];
+    const group = store.typeItems.group[ndx];
     const addIds = [group.id, ...group.ids].filter(
       (aid) => !nIds.includes(aid)
     );
@@ -118,6 +118,7 @@ export const useSelection = installGlobalVar(() => {
     const boxRect = box.getClientRect();
     selections.value = [];
 
+
     for (let i = 0; i < shapeBoxs.length; i++) {
       if (Util.haveIntersection(boxRect, shapeBoxs[i]))
         selections.value.push(shapes[i]);
@@ -371,7 +372,7 @@ export const useSelectionRevise = () => {
           const ids = data.ids;
           const cIds = ids.filter(id => store.getType(id) !== "group")
 
-          const groups = store.data.typeItems.group
+          const groups = store.typeItems.group
           const exists = groups?.some(group => {
             if (group.ids.length !== cIds.length) return false
             const diff = diffArrayChange(group.ids, cIds)

+ 162 - 0
src/core/html-mount/hover-triggle.vue

@@ -0,0 +1,162 @@
+<template>
+  <Teleport :to="`#${DomMountId}`" v-if="stage">
+    <div
+      v-if="pointer"
+      :style="{ transform: pointer }"
+      class="hover-controller"
+      ref="layout"
+    >
+      <slot />
+    </div>
+  </Teleport>
+</template>
+
+<script lang="ts" setup>
+import { computed, nextTick, ref, watch, watchEffect } from "vue";
+import { useStage } from "../hook/use-global-vars.ts";
+import { useMode } from "../hook/use-status.ts";
+import { DC, EntityShape } from "@/deconstruction.js";
+import { useViewerTransformConfig } from "../hook/use-viewer.ts";
+import { Transform } from "konva/lib/Util";
+import { DomMountId } from "@/constant/index.ts";
+import { shapeTreeContain } from "@/utils/shape.ts";
+import { Mode } from "@/constant/mode.ts";
+
+const props = withDefaults(
+  defineProps<{
+    target: DC<EntityShape> | undefined;
+    show?: boolean;
+    formatChild?: boolean;
+  }>(),
+  { show: undefined }
+);
+const emit = defineEmits<{
+  (e: "update:show", v: boolean): void;
+}>();
+
+const layout = ref<HTMLDivElement>();
+const stage = useStage();
+const selfShow = ref(false);
+
+const show = computed(() => (props.show !== undefined ? props.show : selfShow.value));
+
+const updateShow = () => {
+  const shape = props.target?.getNode();
+  const pos = stage.value?.getNode().pointerPos;
+  if (!shape || !pos) return false;
+  let clickShape = stage.value?.getNode().getIntersection(pos);
+  const show = !!clickShape && shapeTreeContain(shape, clickShape) === shape;
+  emit("update:show", (selfShow.value = show));
+};
+
+const mode = useMode();
+watchEffect((onCleanup) => {
+  const dom = stage.value?.getStage().container();
+  if (!dom || mode.value.has(Mode.draw)) return;
+  console.log("moveHandler");
+  dom.addEventListener("mousemove", updateShow);
+  onCleanup(() => {
+    console.log("cancelMoveHandler");
+    dom.removeEventListener("mousemove", updateShow);
+  });
+});
+
+const move = new Transform();
+const pointer = ref<string | null>(null);
+const calcPointer = async () => {
+  const $stage = stage.value!.getStage();
+  const $shape = props.target!.getNode();
+  const shapeRect = $shape.getClientRect();
+
+  const shapeR = shapeRect.x + shapeRect.width;
+  const shapeB = shapeRect.y + shapeRect.height;
+  let x = shapeRect.x + shapeRect.width / 2;
+  let y = shapeRect.y;
+
+  move.reset();
+  move.translate(x, y);
+  pointer.value = `matrix(${move.m.join(",")})`;
+  await nextTick();
+
+  const domRect = layout.value!.getBoundingClientRect();
+  x = x - domRect.width / 2;
+  x = Math.max(x, shapeRect.x);
+
+  if (x + domRect.width > shapeR) {
+    x = shapeR - domRect.width;
+  }
+  if (y + domRect.height > shapeB) {
+    y = y - domRect.height;
+  }
+
+  x = Math.max(x, 10);
+  y = Math.max(y, 10);
+  if (x + domRect.width > $stage.width() - 10) {
+    x = $stage.width() - domRect.width - 10;
+  }
+  if (y + domRect.height > $stage.height() - 10) {
+    y = $stage.height() - domRect.height - 10;
+  }
+
+  move.reset();
+  move.translate(x, y);
+  pointer.value = `matrix(${move.m.join(",")})`;
+};
+
+let timeout: any;
+const resetPointer = () => {
+  if (pointer.value) {
+    return;
+  }
+  clearTimeout(timeout);
+  timeout = setTimeout(calcPointer, 16);
+};
+watch(
+  show,
+  (show: boolean) => {
+    if (show) {
+      resetPointer();
+    } else {
+      pointer.value = null;
+    }
+  },
+  { immediate: true }
+);
+watch(
+  () => props.formatChild,
+  (_a, _b, onCleanup) => {
+    if (props.formatChild) {
+      onCleanup(
+        watch(useViewerTransformConfig(), () => {
+          pointer.value = null;
+          resetPointer();
+        })
+      );
+    }
+  }
+);
+</script>
+
+<style lang="scss" scoped>
+.hover-controller {
+  position: absolute;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+  background-color: #ffffff;
+  left: 0;
+  top: 0;
+  overflow: hidden;
+  color: #303133;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
+  padding: 5px 0;
+  pointer-events: all;
+  font-size: 14px;
+  border: 1px solid var(--el-border-color-light);
+  box-shadow: var(--el-dropdown-menu-box-shadow);
+  background-color: var(--el-bg-color-overlay);
+  border-radius: var(--el-border-radius-base);
+}
+</style>

src/core/propertys/components/checkbox.vue → src/core/html-mount/propertys/components/checkbox.vue


src/core/propertys/components/color.vue → src/core/html-mount/propertys/components/color.vue


src/core/propertys/components/num.vue → src/core/html-mount/propertys/components/num.vue


src/core/propertys/components/proportion.vue → src/core/html-mount/propertys/components/proportion.vue


src/core/propertys/components/select.vue → src/core/html-mount/propertys/components/select.vue


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


+ 4 - 4
src/core/propertys/hover-operate.vue

@@ -27,14 +27,14 @@
 
 <script lang="ts" setup>
 import { computed, nextTick, ref, watch, watchEffect } from "vue";
-import { useStage } from "../hook/use-global-vars.ts";
-import { useMode } from "../hook/use-status.ts";
+import { useStage } from "../../hook/use-global-vars.ts";
+import { useMode } from "../../hook/use-status.ts";
 import { DC, EntityShape } from "@/deconstruction.js";
-import { useViewerTransformConfig } from "../hook/use-viewer.ts";
+import { useViewerTransformConfig } from "../../hook/use-viewer.ts";
 import { Transform } from "konva/lib/Util";
 import { DomMountId } from "@/constant/index.ts";
 import { ElMenu, ElIcon, ElMenuItem } from "element-plus";
-import { useFormalLayer } from "../hook/use-layer.ts";
+import { useFormalLayer } from "../../hook/use-layer.ts";
 import { shapeTreeContain } from "@/utils/shape.ts";
 import { Mode } from "@/constant/mode.ts";
 

src/core/propertys/index.ts → src/core/html-mount/propertys/index.ts


+ 3 - 3
src/core/propertys/mount.vue

@@ -24,11 +24,11 @@
 
 <script lang="ts" setup>
 import { computed, ref, watch } from "vue";
-import { useStage } from "../hook/use-global-vars.ts";
-import { useMode } from "../hook/use-status.ts";
+import { useStage } from "../../hook/use-global-vars.ts";
+import { useMode } from "../../hook/use-status.ts";
 import { PropertyDescribes, propertyComponents } from "./index.ts";
 import { DC, EntityShape } from "@/deconstruction.js";
-import { useMouseShapeStatus } from "../hook/use-mouse-status.ts";
+import { useMouseShapeStatus } from "../../hook/use-mouse-status.ts";
 import { DomOutMountId } from "@/constant/index.ts";
 import { Mode } from "@/constant/mode.ts";
 import { debounce } from "@/utils/shared.ts";

+ 9 - 1
src/core/renderer/renderer.vue

@@ -46,6 +46,7 @@
           <SnapLines />
           <SplitLine v-if="expose.config.showLabelLine" />
           <Compass v-if="config.showCompass" />
+          <layers v-if="store.layers.length > 1" />
           <Debugger v-if="isDev" />
           <Border />
           <!-- <MultipleSelection /> -->
@@ -64,6 +65,7 @@ import SnapLines from "../helper/snap-lines.vue";
 import BackGrid from "../helper/back-grid.vue";
 import SplitLine from "../helper/split-line.vue";
 import Debugger from "../helper/debugger.vue";
+import layers from "../helper/layers.vue";
 import Compass from "../helper/compass.vue";
 import { ShapeType, components } from "../components";
 import {
@@ -77,7 +79,13 @@ import { useMode } from "../hook/use-status.ts";
 import { useViewerTransformConfig } from "../hook/use-viewer.ts";
 import { useGlobalResize } from "../hook/use-event.ts";
 import { useAutoService, useExpose } from "../hook/use-expose.ts";
-import { DataGroupId, DomMountId, DomOutMountId, rendererMap, rendererName } from "../../constant";
+import {
+  DataGroupId,
+  DomMountId,
+  DomOutMountId,
+  rendererMap,
+  rendererName,
+} from "../../constant";
 import { useStore } from "../store/index.ts";
 import { Mode } from "@/constant/mode.ts";
 import { computed, getCurrentInstance, onUnmounted, ref, watch } from "vue";

+ 22 - 7
src/core/store/index.ts

@@ -37,10 +37,8 @@ type DSRAction = {
 };
 
 export type DrawStoreBusArgs = EDSR<
-  { dataChange: void } & FilterKeysWithPrefix<
-    FilterNever<DSRAction>,
-    "$" | "get"
-  >
+  { dataChange: void } 
+  & FilterKeysWithPrefix<FilterNever<DSRAction>, "$" | "get" >
 >;
 
 export type DrawStore = DSR & { bus: Emitter<DrawStoreBusArgs> };
@@ -55,29 +53,45 @@ export const useStore = installGlobalVar(() => {
     store.$patch((state) => {
       store.bus.emit('dataChangeBefore')
       state.data = data;
+      console.log(data)
       nextTick(() => store.bus.emit("dataChangeAfter"))
     });
   });
 
   const trackActions = [
     "setStore",
-    "repStore",
     "addItem",
     "addItems",
     "delItem",
     "setItem",
     "setConfig",
+    "delLayer",
+    "addLayer"
   ];
+  const emitActions = [
+    ...trackActions,
+    'setCurrentLayer'
+  ]
+  let prevLayer: string 
   let isRuning = false;
   store.$onAction(({ name, after, args }) => {
-    if (!trackActions.includes(name)) return;
+    if (!emitActions.includes(name)) return;
     let currentIsRuning = isRuning;
     isRuning = true;
     store.bus.emit((name + "Before") as any, args);
     nextTick(() => store.bus.emit((name + "After") as any, args))
-    
+
     if (currentIsRuning) {
       return;
+    } else if (!trackActions.includes(name)) {
+      isRuning = false;
+      return
+    }
+
+    if (prevLayer && prevLayer !== store.currentLayer) {
+      history.push(
+        JSON.stringify({...store.data, __currentLayer: store.currentLayer})
+      );
     }
 
     after(() => {
@@ -87,6 +101,7 @@ export const useStore = installGlobalVar(() => {
         history.push(JSON.stringify(store.data));
       }
       isRuning = false;
+      prevLayer = store.currentLayer
     });
   });
   return store;

+ 99 - 27
src/core/store/store.ts

@@ -1,5 +1,6 @@
 import { defineStore } from "pinia";
 import { DrawData, DrawItem, ShapeType } from "../components";
+import { defaultLayer } from "@/constant";
 
 const sortFn = (
   a: Pick<DrawItem, "zIndex" | "createTime">,
@@ -10,25 +11,48 @@ export type StoreConfig = {
   compass: {
     rotation: number;
     url?: string;
-  }
+  };
 };
 export type StoreData = {
-  typeItems: DrawData;
+  layers: Record<string, DrawData>,
   config: StoreConfig;
+  __currentLayer: string;
 };
 const defConfig: StoreData["config"] = {
   compass: { rotation: 0 },
 };
 
 export const getEmptyStoreData = (): StoreData => {
-  return { typeItems: {}, config: { ...defConfig } };
+  return {
+    layers: {},
+    config: { ...defConfig },
+    __currentLayer: defaultLayer,
+  };
 };
 
 export const useStoreRaw = defineStore("draw-data", {
   state: () => ({ data: getEmptyStoreData() }),
   getters: {
+    currentLayer() {
+      const layer = (this as any).data.__currentLayer
+      const layers = (this as any).layers
+      if (layers.includes(layer)) {
+        return layer
+      } else {
+        return layers[0]
+      }
+    },
+    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] || {}
+    },
     items() {
-      return Object.values((this as any).data.typeItems).flat() as DrawItem[];
+      return Object.values(this.typeItems).flat() as DrawItem[];
     },
     sortItems() {
       return (this.items as any).sort(sortFn) as DrawItem[];
@@ -38,48 +62,55 @@ export const useStoreRaw = defineStore("draw-data", {
     },
   },
   actions: {
-    repStore(store: StoreData) {
-      const newStore = JSON.parse(JSON.stringify(store));
-      this.$patch((state) => {
-        state.data = newStore;
-      });
-    },
     setStore(store: Partial<StoreData>) {
-      const newStore = JSON.parse(JSON.stringify(store));
+      const newStore = JSON.parse(JSON.stringify(store)) ;
       this.$patch((state) => {
-        state.data = newStore;
+        console.log(state.data)
+        state.data = {
+          ...state.data,
+          ...newStore
+        };
+        console.log(state.data)
       });
     },
+    setLayerStore(layerStore: DrawData) {
+      this.$patch(state => {
+        state.data.layers[this.currentLayer] = layerStore
+      })
+    },
     getItemNdx<T extends ShapeType>(type: T, id: string) {
-      const items = this.data.typeItems[type];
+      const items = this.typeItems[type];
+      
       if (items) {
         return items.findIndex((item) => item.id === id);
       }
       return -1;
     },
     getTypeItems<T extends ShapeType>(type: T): DrawItem<T>[] {
-      return (this.data.typeItems[type] as DrawItem<T>[]) || [];
+      return (this.typeItems[type] as DrawItem<T>[]) || [];
     },
     getItem<T extends ShapeType>(type: T, id: string) {
       const ndx = this.getItemNdx(type, id);
-      if (~ndx) return this.data.typeItems[type]![ndx];
+      if (~ndx) return this.typeItems[type]![ndx];
     },
     addItems<T extends ShapeType>(type: T, items: DrawItem<T>[]) {
       items.forEach((item) => this.addItem(type, item));
     },
     addItem<T extends ShapeType>(type: T, item: DrawItem<T>) {
-      this.$patch((state) => {
-        if (!(type in state.data.typeItems)) {
-          state.data.typeItems[type] = [];
+      const typeItems = this.typeItems
+      this.$patch(() => {
+        if (!(type in typeItems)) {
+          typeItems[type] = [];
         }
-        state.data.typeItems[type]!.push(item as any);
+        typeItems[type]!.push(item as any);
       });
     },
     delItem<T extends ShapeType>(type: T, id: string) {
       const ndx = this.getItemNdx(type, id);
+      const typeItems = this.typeItems
       if (~ndx) {
-        this.$patch((state) => {
-          state.data.typeItems[type]!.splice(ndx, 1);
+        this.$patch(() => {
+          typeItems[type]!.splice(ndx, 1);
         });
       }
     },
@@ -87,10 +118,11 @@ export const useStoreRaw = defineStore("draw-data", {
       type: T,
       playData: { value: Partial<DrawItem<T>>; id: string }
     ) {
+      const typeItems = this.typeItems
       const ndx = this.getItemNdx(type, playData.id);
       if (~ndx) {
-        this.$patch((state) => {
-          Object.assign(state.data.typeItems[type]![ndx], playData.value);
+        this.$patch(() => {
+          Object.assign(typeItems[type]![ndx], playData.value);
         });
       }
     },
@@ -102,17 +134,18 @@ export const useStoreRaw = defineStore("draw-data", {
       }
     },
     getType(id: string) {
-      const types = Object.keys(this.data.typeItems) as ShapeType[];
+      const typeItems = this.typeItems
+      const types = Object.keys(typeItems) as ShapeType[];
       for (const type of types) {
-        if (this.data.typeItems[type]?.some((item) => item.id === id)) {
+        if (typeItems[type]?.some((item) => item.id === id)) {
           return type;
         }
       }
     },
     getItemById(id: string) {
-      const types = Object.keys(this.data.typeItems) as ShapeType[];
+      const types = Object.keys(this.typeItems) as ShapeType[];
       for (const type of types) {
-        const item = this.data.typeItems[type]?.find((item) => item.id === id);
+        const item = this.typeItems[type]?.find((item) => item.id === id);
         if (item) {
           return item;
         }
@@ -123,5 +156,44 @@ export const useStoreRaw = defineStore("draw-data", {
         state.data.config = config;
       });
     },
+    setCurrentLayer(layer: string) {
+      if (!this.layers.includes(layer)) {
+        throw `不存在${layer}层`
+      } else {
+        this.data.__currentLayer = layer
+      }
+    },
+    addLayer(layer: string) {
+      if (this.layers.includes(layer)) {
+        throw `已存在${layer}层`
+      } else {
+        this.data.layers[layer] = {}
+      }
+    },
+    delLayer(layer: string, translateLayer?: string) {
+      if (!this.layers.includes(layer)) {
+        return;
+      }
+
+      if (translateLayer) {
+        if (!this.layers.includes(translateLayer)) {
+          throw `不存在${translateLayer}层`
+        }
+        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
+          } else {
+            tLayerData[key] = layerData[key] as any
+          }
+        }
+      }
+    }
   },
 });

+ 1 - 1
src/example/fuse/views/home.vue

@@ -35,7 +35,7 @@ installDraw(draw);
 const initData = async () => {
   const data = await getData();
   const viewport = await getViewport();
-  draw.value?.store.repStore(data);
+  draw.value?.store.setStore(data);
   viewport && draw.value?.viewer.setViewMat(viewport);
 };
 initData();

Fichier diff supprimé car celui-ci est trop grand
+ 967 - 962
src/example/fuse/views/test.ts