bill 5 месяцев назад
Родитель
Сommit
8badea6af1

+ 2 - 3
src/core/components/bg-image/index.ts

@@ -7,6 +7,7 @@ import {
 } from "../util.ts";
 import { imageInfo } from "@/utils/resource.ts";
 import { InteractiveFix, InteractiveTo } from "../index.ts";
+import { Size } from "@/utils/math.ts";
 
 export { default as Component } from "./bg-image.vue";
 export { default as TempComponent } from "./temp-bg-image.vue";
@@ -42,10 +43,8 @@ export const getSnapPoints = (data: BGImageData) => {
 };
 
 export type BGImageData = Partial<typeof defaultStyle> &
-  BaseItem & {
+  BaseItem & Size & {
     cornerRadius: number;
-    width: number;
-    height: number;
     url: string;
     mat: number[];
   };

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

@@ -13,12 +13,11 @@
 import TempIcon from "./temp-icon.vue";
 import { IconData, getMouseStyle, defaultStyle } from "./index.ts";
 import { useComponentStatus } from "@/core/hook/use-component.ts";
-import { PropertyUpdate, Operate, PropertyKeys, mergeDescribes } from "../../propertys";
+import { PropertyUpdate, Operate, mergeDescribes } from "../../propertys";
 import { Transform } from "konva/lib/Util";
 import originDescribes from "../../propertys/describes.json";
 import { ref } from "vue";
 import { MathUtils } from "three";
-import { rangMod } from "@/utils/shared.ts";
 
 const props = defineProps<{ data: IconData }>();
 const emit = defineEmits<{

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

@@ -9,6 +9,7 @@ import {
 import { getMouseColors } from "@/utils/colors.ts";
 import { FixScreen } from "@/utils/bound.ts";
 import { InteractiveFix, InteractiveTo } from "../index.ts";
+import { Size } from "@/utils/math.ts";
 
 export { default as Component } from "./icon.vue";
 export { default as TempComponent } from "./temp-icon.vue";
@@ -51,15 +52,13 @@ export const getMouseStyle = (data: IconData) => {
 };
 
 export type IconData = Partial<typeof defaultStyle> &
-  BaseItem & {
+  BaseItem & Size & {
     fill?: string;
     stroke?: string;
     strokeWidth?: number;
     coverFill?: string;
     coverStroke?: string;
     coverStrokeWidth?: number;
-    width: number;
-    height: number;
     mat: number[];
     url: string;
     fixScreen?: FixScreen;

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

@@ -8,6 +8,7 @@ import {
 import { getMouseColors } from "@/utils/colors.ts";
 import { imageInfo } from "@/utils/resource.ts";
 import { InteractiveFix, InteractiveTo } from "../index.ts";
+import { Size } from "@/utils/math.ts";
 
 export { default as Component } from "./image.vue";
 export { default as TempComponent } from "./temp-image.vue";
@@ -48,13 +49,11 @@ export const getSnapPoints = (data: ImageData) => {
 };
 
 export type ImageData = Partial<typeof defaultStyle> &
-  BaseItem & {
+  BaseItem & Size & {
     fill?: string;
     stroke?: string;
     strokeWidth?: number;
     cornerRadius: number;
-    width: number;
-    height: number;
     url: string;
     mat: number[];
   };

+ 3 - 6
src/core/components/table/index.ts

@@ -8,6 +8,7 @@ import {
 } from "../util.ts";
 import { getMouseColors } from "@/utils/colors.ts";
 import { InteractiveFix, InteractiveTo } from "../index.ts";
+import { Size } from "@/utils/math.ts";
 
 export { default as Component } from "./table.vue";
 export { default as TempComponent } from "./temp-table.vue";
@@ -31,22 +32,18 @@ export const defaultCollData = {
 
 export const addMode = "area";
 
-export type TableCollData = Partial<typeof defaultCollData> & {
+export type TableCollData = Partial<typeof defaultCollData> & Size & {
   content: string;
-  width: number;
-  height: number;
   padding: number
   readonly?: boolean
   notdel?: boolean
 };
 export type TableData = Partial<typeof defaultStyle> &
-  BaseItem & {
+  BaseItem & Size & {
     notaddRow?: boolean
     notaddCol?: boolean
     mat: number[];
     content: TableCollData[][];
-    width: number;
-    height: number;
   };
 
 export const getMouseStyle = (data: TableData) => {

+ 93 - 0
src/core/helper/compass.vue

@@ -0,0 +1,93 @@
+<template>
+  <TempIcon :data="{ ...data, ...style, mat }" :ref="(e: any) => shape = e?.shape" />
+  <PropertyUpdate
+    :describes="describes"
+    :data="data"
+    :target="shape"
+    @change="changeHandler"
+  />
+</template>
+
+<script lang="ts" setup>
+import TempIcon from "../components/icon/temp-icon.vue";
+import { PropertyUpdate, mergeDescribes } from "../propertys";
+import { computed, ref, watch } 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 { useConfig } from "../hook/use-config.ts";
+import { Transform } from "konva/lib/Util";
+import { getFixPosition } from "@/utils/bound.ts";
+import { useResize } from "../hook/use-event.ts";
+import { MathUtils } from "three";
+
+const config = useConfig();
+const data = ref({
+  coverFill: themeMouseColors.theme,
+  coverOpcatiy: 0,
+  strokeScaleEnabled: false,
+  width: 80,
+  height: 80,
+  rotation: 0,
+  url: config.compass?.url || "icons/edit_compass.svg",
+});
+
+watch(
+  () => config.compass!.url,
+  (url) => {
+    data.value.url = url || "icons/edit_compass.svg";
+  }
+);
+
+const shape = ref<DC<Group>>();
+const [style] = useAnimationMouseStyle({
+  data: data as any,
+  shape,
+  getMouseStyle: () => {
+    const fillStatus = getMouseColors(data.value.coverFill);
+    return {
+      default: {
+        coverFill: fillStatus.pub,
+      },
+      hover: { coverFill: fillStatus.hover },
+      press: { coverFill: fillStatus.press },
+    };
+  },
+}) as any;
+
+const other = ref({ rotate: config.compass!.rotation });
+watch(
+  () => config.compass!.rotation,
+  (val) => {
+    other.value.rotate = val;
+  }
+);
+const changeHandler = () => {
+  config.compass!.rotation = other.value.rotate;
+};
+
+const describes = mergeDescribes(other, {}, ["rotate"]);
+describes.rotate = {
+  ...describes.rotate,
+  sort: 3,
+  get value() {
+    return other.value.rotate;
+  },
+  set value(val) {
+    other.value.rotate = val;
+  },
+};
+
+const size = useResize();
+const mat = computed(() => {
+  if (!size.value) return;
+
+  const tf = new Transform();
+  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;
+});
+</script>

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

@@ -183,7 +183,7 @@ export type UseComponentStatusProps<
     data: Ref<T>
   ) => void;
   getRepShape?: () => Shape;
-  copyHandler: (transform: Transform, data: T) => T;
+  copyHandler?: (transform: Transform, data: T) => T;
 };
 
 export const useComponentStatus = <S extends EntityShape, T extends DrawItem>(
@@ -277,7 +277,7 @@ export const useComponentsAttach = <T>(
   for (const type of types) {
     cleanups.push(
       globalWatch(
-        () => store.data[type]?.map((item) => item),
+        () => store.getTypeItems(type),
         (items, _, onCleanup) => {
           if (!items) return;
           for (const item of items) {

+ 76 - 0
src/core/hook/use-config.ts

@@ -0,0 +1,76 @@
+import { computed, nextTick, reactive } from "vue";
+import { installGlobalVar } from "./use-global-vars";
+import { useGlobalResize } from "./use-event";
+import { Size } from "@/utils/math";
+import { useStore } from "../store";
+import { StoreConfig } from "../store/store";
+
+export type Border = {
+  color?: string;
+  opacity: number;
+  margin: number[] | number;
+  lineWidth: number;
+};
+
+export type Config = {
+  showGrid: boolean;
+  showLabelLine: boolean;
+  size: Size | null;
+  back?: { color?: string; opacity: number };
+  border?: Border | Border[];
+  margin?: number | number[];
+  showCompass: boolean
+
+};
+
+export const defConfig: Config = {
+  showGrid: true,
+  showLabelLine: true,
+  size: null,
+  showCompass: false
+};
+
+export const useConfig = installGlobalVar(() => {
+  const { setFixSize, size } = useGlobalResize();
+  const store = useStore();
+
+  let repConfig = { ...store.config };
+  let isWait = false;
+  const setConfig = <T extends keyof StoreConfig>(
+    key: T,
+    val: StoreConfig[T]
+  ) => {
+    repConfig[key] = val;
+    if (isWait) return;
+    isWait = true
+    nextTick(() => {
+      store.setConfig(repConfig);
+      isWait = false;
+      repConfig = { ...store.config };
+    });
+  };
+
+  const fast = <T extends keyof StoreConfig>(key: T) =>
+    computed({
+      get: () => store.config[key],
+      set: (val: StoreConfig[T]) => {
+        setConfig(key, val);
+      },
+    });
+
+    
+  return reactive({
+    ...defConfig,
+    compass: fast('compass'),
+    proportion: fast("proportion"),
+    size: computed({
+      get: () => size.value!,
+      set: (size: Size | null) => {
+        setFixSize(size)
+      },
+    }),
+    showCompass: false,
+    showGrid: true,
+    showLabelLine: true,
+  }) as Config & StoreConfig;
+});

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

@@ -36,7 +36,7 @@ import { useHistory, useHistoryAttach } from "./use-history";
 import penA from "../assert/cursor/pic_pen_a.ico";
 import penR from "../assert/cursor/pic_pen_r.ico";
 import { useCurrentZIndex } from "./use-layer";
-import { useViewerInvertTransform, useViewerTransform } from "./use-viewer";
+import { useViewerTransform } from "./use-viewer";
 
 type PayData<T extends ShapeType> = ComponentValue<T, "addMode"> extends "area"
   ? Area
@@ -81,6 +81,7 @@ export const useInteractiveDrawShapeAPI = installGlobalVar(() => {
   return {
     delShape(id: string) {
       const type = store.getType(id);
+      console.log(type, id)
       type && store.delItem(type, id);
     },
     addShape: <T extends ShapeType>(

+ 2 - 1
src/core/hook/use-event.ts

@@ -1,3 +1,4 @@
+import { Size } from "@/utils/math.ts";
 import { listener } from "../../utils/event.ts";
 import { installGlobalVar, useStage } from "./use-global-vars.ts";
 import { nextTick, ref, watchEffect } from "vue";
@@ -30,7 +31,7 @@ export const useListener = <
 
 export const useGlobalResize = installGlobalVar(() => {
   const stage = useStage();
-  const size = ref<{ width: number; height: number }>();
+  const size = ref<Size>();
   const setSize = () => {
     if (fix.value) return;
     const container = stage.value?.getStage().container();

+ 4 - 29
src/core/hook/use-expose.ts

@@ -23,6 +23,7 @@ import { mergeFuns } from "@/utils/shared.ts";
 import { themeColor } from "@/constant/help-style.ts";
 import { isSvgString } from "@/utils/resource.ts";
 import { useResourceHandler } from "./use-fetch.ts";
+import { useConfig } from "./use-config.ts";
 
 export const useAutoService = () => {
   // 自动粘贴服务
@@ -132,6 +133,7 @@ export const useAutoService = () => {
   });
 };
 
+
 export type DrawExpose = ReturnType<typeof useExpose>;
 type PickParams<K extends keyof Stage, O extends string> = Stage[K] extends (
   ...args: any
@@ -139,13 +141,6 @@ type PickParams<K extends keyof Stage, O extends string> = Stage[K] extends (
   ? Omit<Required<Parameters<Stage[K]>>[0], O>
   : never;
 
-export type Border = {
-  color?: string;
-  opacity: number;
-  margin: number[] | number;
-  lineWidth: number;
-};
-
 export const useExpose = installGlobalVar(() => {
   const mode = useMode();
   const interactiveProps = useInteractiveProps();
@@ -154,27 +149,7 @@ export const useExpose = installGlobalVar(() => {
   const store = useStore();
   const history = useHistory();
   const viewer = useViewer().viewer;
-  const { updateSize, setFixSize, size } = useGlobalResize();
-  const config = reactive({
-    showGrid: true,
-    showLabelLine: true,
-    get size() {
-      return size.value!;
-    },
-    set size(csize: { width: number; height: number } | null) {
-      setFixSize(csize);
-    },
-  }) as Config;
-
-  type Config = {
-    showGrid: boolean;
-    showLabelLine: boolean;
-    back?: { color?: string; opacity: number };
-    border?: Border | Border[];
-    margin?: number | number[];
-    size?: {width: number, height: number}
-  };
-
+  const { updateSize } = useGlobalResize();
   const exposeBlob = (config?: PickParams<"toBlob", "callback">) => {
     const $stage = stage.value!.getStage();
     return new Promise<Blob>((resolve) => {
@@ -206,6 +181,6 @@ export const useExpose = installGlobalVar(() => {
     },
     viewer,
     presetAdd: interactiveProps,
-    config,
+    config: useConfig(),
   };
 });

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

@@ -22,7 +22,7 @@ import { Layer } from "konva/lib/Layer";
 import { Pos } from "@/utils/math.ts";
 import { listener } from "@/utils/event.ts";
 import { mergeFuns, onlyId } from "@/utils/shared.ts";
-import { DrawData } from "../components/index.ts";
+import { StoreData } from "../store/store.ts";
 
 export const installGlobalVar = <T>(
   create: () => { var: T; onDestroy: () => void } | T,
@@ -69,7 +69,7 @@ export const installGlobalVar = <T>(
 
 export type InstanceProps = {
   id?: string;
-  data: DrawData;
+  data?: StoreData;
   handlerResource(file: File): Promise<string>;
 };
 export const useInstanceProps = installGlobalVar(() => {

+ 9 - 5
src/core/hook/use-history.ts

@@ -1,10 +1,9 @@
 import mitt from "mitt";
 import { SingleHistory } from "../history";
 import { installGlobalVar } from "./use-global-vars";
-import { DrawData } from "../components";
 import { Ref, ref, watch } from "vue";
 import { copy } from "@/utils/shared";
-import { useStoreRaw } from "../store/store";
+import { getEmptyStoreData, StoreData, useStoreRaw } from "../store/store";
 
 type HistoryItem = { attachs: string; data: string };
 export class DrawHistory {
@@ -25,6 +24,7 @@ export class DrawHistory {
   onceFlag = false;
   onceHistory: string | null = null;
   initData: string | null = null;
+  clearData: string = ''
   renderer: (data: HistoryItem) => void;
   bus = mitt<{
     attachs: Record<string, any>;
@@ -43,6 +43,10 @@ export class DrawHistory {
       this.bus.emit("attachs", attachs ? JSON.parse(attachs) : {});
     };
   }
+
+  setClearData(data:string = '') {
+    this.clearData = data
+  }
   
   clearHistoryAttach(id: string, name: string) {
     const history = this.history.history as any
@@ -159,8 +163,8 @@ export class DrawHistory {
   }
 
   clearCurrent(): void {
-    this.renderer({ data: "", attachs: "" });
-    this.push("");
+    this.renderer({ data: this.clearData, attachs: "" });
+    this.push(this.clearData);
   }
 
   clear(): void {
@@ -179,7 +183,7 @@ export class DrawHistory {
 export const useHistory = installGlobalVar(() => {
   const store = useStoreRaw();
   const history = new DrawHistory((dataStr: string) => {
-    const data: DrawData = dataStr ? JSON.parse(dataStr) : {};
+    const data: StoreData = dataStr ? JSON.parse(dataStr) : getEmptyStoreData()
     store.$patch((state) => {
       state.data = data;
     });

+ 6 - 10
src/core/hook/use-layer.ts

@@ -183,22 +183,18 @@ export const useCurrentZIndex = () => {
   return {
     get max() {
       let cur = Number.MIN_VALUE 
-      for (const items of Object.values(store.data)) {
-        for (const item of items) {
-          if (cur < item.zIndex) {
-            cur = item.zIndex
-          }
+      for (const item of store.items) {
+        if (cur < item.zIndex) {
+          cur = item.zIndex
         }
       }
       return cur
     },
     get min() {
       let cur = Number.MAX_VALUE 
-      for (const items of Object.values(store.data)) {
-        for (const item of items) {
-          if (cur > item.zIndex) {
-            cur = item.zIndex
-          }
+      for (const item of store.items) {
+        if (cur > item.zIndex) {
+          cur = item.zIndex
         }
       }
       return cur

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

@@ -49,7 +49,7 @@ const useStoreSnapInfos = () => {
 
     cleanups.push(
       globalWatch(
-        () => store.data[type]?.map((item) => item),
+        () => store.getTypeItems(type),
         (items, _, onCleanup) => {
           if (!items) return;
           for (const item of items) {

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

@@ -22,6 +22,6 @@ const props = defineProps<{ type: ShapeType }>();
 const store = useStore();
 const type = props.type as "arrow";
 const ShapeComponent = components[type].Component;
-const items = computed(() => store.data[type] || []);
+const items = computed(() => store.getTypeItems(type));
 const { itemHasRegistor, renderer } = useStoreRenderProcessors();
 </script>

+ 12 - 3
src/core/renderer/renderer.vue

@@ -31,6 +31,7 @@
           </template>
         </v-layer>
         <v-layer id="helper">
+          <Compass v-if="config.showCompass" />
           <ActiveBoxs />
           <SnapLines />
           <SplitLine v-if="expose.config.showLabelLine" />
@@ -52,6 +53,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 Compass from "../helper/compass.vue";
 import { ShapeType, components } from "../components";
 import {
   InstanceProps,
@@ -61,20 +63,26 @@ import {
   useStage,
 } from "../hook/use-global-vars.ts";
 import { useViewerTransformConfig } from "../hook/use-viewer.ts";
-import { useGlobalResize, useResize } from "../hook/use-event.ts";
+import { useGlobalResize } from "../hook/use-event.ts";
 import { useAutoService, useExpose } from "../hook/use-expose.ts";
 import { DomMountId, DomOutMountId } from "../../constant";
 import { useStore } from "../store/index.ts";
 import { Mode } from "@/constant/mode.ts";
-import { computed, getCurrentInstance, ref } from "vue";
+import { computed, getCurrentInstance, ref, watch } from "vue";
 import { install } from "../../install-lib.ts";
+import { useConfig } from "../hook/use-config.ts";
+import { getEmptyStoreData } from "../store/store.ts";
 
 const instance = getCurrentInstance();
 install(instance!.appContext.app);
 
 const props = defineProps<InstanceProps>();
 const store = useStore();
-store.setStore(props.data);
+watch(
+  () => props.data,
+  (data) => store.setStore(data || getEmptyStoreData())
+);
+
 useInstanceProps().set(props);
 useAutoService();
 
@@ -85,6 +93,7 @@ const layout = ref();
 const viewerConfig = useViewerTransformConfig();
 const types = Object.keys(components) as ShapeType[];
 const mode = useMode();
+const config = useConfig();
 
 const GroupComponentMap = types.reduce((map, type) => {
   map[type] = components[type].GroupComponent || ShapeGroup;

+ 1 - 0
src/core/store/index.ts

@@ -32,6 +32,7 @@ export const useStore = installGlobalVar(() => {
     "addItem",
     "delItem",
     "setItem",
+    "setConfig"
   ];
   store.$onAction(({ name, after, store }) => {
     if (!trackActions.includes(name)) return;

+ 126 - 94
src/core/store/store.ts

@@ -1,98 +1,130 @@
 import { defineStore } from "pinia";
-import { DrawData, DrawItem, ShapeType } from '../components'
+import { DrawData, DrawItem, ShapeType } from "../components";
 
-const sortFn = (a: Pick<DrawItem, 'zIndex' | 'createTime'>, b: Pick<DrawItem, 'zIndex' | 'createTime'>) => 
-	a.zIndex - b.zIndex || a.createTime - b.createTime
+const sortFn = (
+  a: Pick<DrawItem, "zIndex" | "createTime">,
+  b: Pick<DrawItem, "zIndex" | "createTime">
+) => a.zIndex - b.zIndex || a.createTime - b.createTime;
 
+export type StoreConfig = {
+  compass: {
+    rotation: number;
+    url?: string;
+  };
+  proportion: { scale: number; unit?: string };
+};
+export type StoreData = {
+  typeItems: DrawData;
+  config: StoreConfig;
+};
+const defConfig: StoreData["config"] = {
+  compass: { rotation: 0 },
+  proportion: { scale: 1 },
+};
 
-export const useStoreRaw = defineStore('draw-data', {
-	state: (): { data: DrawData, version: number } => ({ version: 0, data: {} }),
-	getters: {
-		items() {
-			return Object.values((this as any).data).flat() as DrawItem[]
-		},
-		sortItems() {
-			return (this.items as any).sort(sortFn) as DrawItem[]
-		}
-	},
-	actions: {
-		repStore(store: DrawData) {
-			const newStore = JSON.parse(JSON.stringify(store))
-			this.$patch(state => {
-				state.data = newStore
-			})
-		},
-		setStore(store: DrawData) {
-			const newStore = JSON.parse(JSON.stringify(store))
-			this.$patch(state => {
-				state.data = newStore
-				state.version = 0
-			})
-		},
-		getItemNdx<T extends ShapeType>(type: T, id: string) {
-			const items = this.data[type]
-			if (items) {
-				return items.findIndex(item => item.id === id)
-			}
-			return -1
-		},
-		getTypeItems<T extends ShapeType>(type: T): DrawItem<T>[] {
-			return this.data[type] as DrawItem<T>[] || []
-		},
-		getItem<T extends ShapeType>(type: T, id: string) {
-			const ndx = this.getItemNdx(type, id)
-			if (~ndx) return this.data[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)) {
-					state.data[type] = []
-				}
-				state.data[type]!.push(item as any);
-			})
-		},
-		delItem<T extends ShapeType>(type: T, id: string) {
-			const ndx = this.getItemNdx(type, id)
-			if (~ndx) {
-				this.$patch(state => {
-					state.data[type]!.splice(ndx, 1)
-				})
-			}
-		},
-		setItem<T extends ShapeType>(type: T, playData: { value: Partial<DrawItem<T>>, id: string }) {
-			const ndx = this.getItemNdx(type, playData.id)
-			if (~ndx) {
-				this.$patch(state => {
-					Object.assign(state.data[type]![ndx], playData.value)
-				})
-			}
-		},
-		getItemsZIndex(items?: DrawItem[]) {
-			if (!items) {
-				return this.sortItems;
-			} else {
-				return items.sort(sortFn)
-			}
-		},
-		getType(id: string) {
-			const types = Object.keys(this.data) as ShapeType[]
-			for (const type of types) {
-				if (this.data[type]?.some(item=> item.id === id)) {
-					return type
-				}
-			}
-		},
-		getItemById(id: string) {
-			const types = Object.keys(this.data) as ShapeType[]
-			for (const type of types) {
-				const item = this.data[type]?.find(item=> item.id === id)
-				if (item) {
-					return item;
-				}
-			}
-		}
-	}
-})
+export const getEmptyStoreData = (): StoreData => {
+  return { typeItems: {}, config: { ...defConfig } };
+};
+
+export const useStoreRaw = defineStore("draw-data", {
+  state: () => ({ data: getEmptyStoreData() }),
+  getters: {
+    items() {
+      console.log(this.data);
+      return Object.values((this as any).data.typeItems).flat() as DrawItem[];
+    },
+    sortItems() {
+      return (this.items as any).sort(sortFn) as DrawItem[];
+    },
+    config() {
+      return (this as any).data.config as StoreData["config"];
+    },
+  },
+  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));
+      this.$patch((state) => {
+        state.data = newStore;
+      });
+    },
+    getItemNdx<T extends ShapeType>(type: T, id: string) {
+      const items = this.data.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>[]) || [];
+    },
+    getItem<T extends ShapeType>(type: T, id: string) {
+      const ndx = this.getItemNdx(type, id);
+      if (~ndx) return this.data.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)) {
+          state.data.typeItems[type] = [];
+        }
+        state.data.typeItems[type]!.push(item as any);
+      });
+    },
+    delItem<T extends ShapeType>(type: T, id: string) {
+      const ndx = this.getItemNdx(type, id);
+      if (~ndx) {
+        this.$patch((state) => {
+          state.data.typeItems[type]!.splice(ndx, 1);
+        });
+      }
+    },
+    setItem<T extends ShapeType>(
+      type: T,
+      playData: { value: Partial<DrawItem<T>>; id: string }
+    ) {
+      const ndx = this.getItemNdx(type, playData.id);
+      if (~ndx) {
+        this.$patch((state) => {
+          Object.assign(state.data.typeItems[type]![ndx], playData.value);
+        });
+      }
+    },
+    getItemsZIndex(items?: DrawItem[]) {
+      if (!items) {
+        return this.sortItems;
+      } else {
+        return items.sort(sortFn);
+      }
+    },
+    getType(id: string) {
+      const types = Object.keys(this.data.typeItems) as ShapeType[];
+      for (const type of types) {
+        if (this.data.typeItems[type]?.some((item) => item.id === id)) {
+          return type;
+        }
+      }
+    },
+    getItemById(id: string) {
+      const types = Object.keys(this.data) as ShapeType[];
+      for (const type of types) {
+        const item = this.data.typeItems[type]?.find((item) => item.id === id);
+        if (item) {
+          return item;
+        }
+      }
+    },
+    setConfig(config: StoreData["config"]) {
+      this.$patch((state) => {
+        state.data.config = config;
+      });
+    },
+  },
+});

+ 2 - 2
src/example/fuse/views/header/header.vue

@@ -71,7 +71,7 @@ import { animation } from "@/core/hook/use-animation.ts";
 const draw = useDraw();
 const bgFileInput = ref<HTMLInputElement | null>(null);
 
-const emit = defineEmits<{ (e: "full"): void; (e: "save"): void; (e: "expose"): void }>();
+const emit = defineEmits<{ (e: "full"): void; (e: "save"): any; (e: "expose"): void }>();
 
 const setBGImage = (file: File) => {
   draw.addShape(
@@ -88,7 +88,7 @@ const setBGImage = (file: File) => {
 };
 
 const rotateView = () => {
-  const dom = draw.stage.container();
+  const dom = draw.stage!.container();
   let rotated = 0;
   animation({ rotation: 0 }, { rotation: Math.PI / 2 }, ({ rotation }) => {
     draw.viewer.rotatePixel(

+ 14 - 10
src/example/fuse/views/home.vue

@@ -1,14 +1,19 @@
 <template>
   <div class="layout" :class="{ full }">
-    <Header class="header" v-if="draw" @full="fullHandler" @save="saveHandler" />
+    <Header
+      class="header"
+      v-if="draw"
+      @full="fullHandler"
+      @save="() => draw && saveData(draw.getData())"
+    />
     <div class="container">
       <Slide class="slide" v-if="draw" />
       <div class="content" ref="drawEle">
         <DrawBoard
           v-if="drawEle"
-          :handler-resource="handlerResource"
+          :handler-resource="uploadResourse"
           ref="draw"
-          :data="(data as any)"
+          :data="data"
         />
       </div>
     </div>
@@ -20,23 +25,22 @@ import Header from "./header/header.vue";
 import Slide from "./slide/slide.vue";
 import { onUnmounted, ref, watch } from "vue";
 import { DrawExpose, DrawBoard } from "@/index";
-import { data, save } from "./init.ts";
 import { installDraw } from "./use-draw.ts";
 import { listener } from "@/utils/event.ts";
 import { ElMessage } from "element-plus";
 import { startAnimation } from "@/utils/shared.ts";
+import { saveData, getData, uploadResourse } from "./req.ts";
+import { StoreData } from "@/core/store/store.ts";
 
 const drawEle = ref<HTMLDivElement | null>(null);
 const draw = ref<DrawExpose>();
 installDraw(draw);
 
-const saveHandler = () => {
-  save(draw.value?.getData());
-};
-
-const handlerResource = async (file: File) => {
-  return URL.createObjectURL(file);
+const data = ref<StoreData>();
+const initData = async () => {
+  data.value = await getData();
 };
+initData();
 
 const full = ref(false);
 watch(full, (_f1, _f2, onCleanup) => {

Разница между файлами не показана из-за своего большого размера
+ 0 - 1198
src/example/fuse/views/init.ts


+ 17 - 0
src/example/fuse/views/req.ts

@@ -0,0 +1,17 @@
+import { StoreData } from '@/core/store/store';
+import { initData } from './test'
+import { asyncTimeout } from '@/utils/shared';
+
+export const getData = async () => {
+  const dataStr = localStorage.getItem("draw-data");
+  await asyncTimeout(1000)
+  return (dataStr ? JSON.parse(dataStr) : initData) as StoreData;
+}
+
+export const saveData = async (data: StoreData) => {
+  localStorage.setItem("draw-data", JSON.stringify(data));
+}
+
+export const uploadResourse = async (file: File) => {
+  return URL.createObjectURL(file);
+};

+ 1 - 1
src/example/fuse/views/slide/handler-menu.ts

@@ -27,7 +27,7 @@ export const handlerMenus = [
         icon: "",
         name: "满屏",
         handler: (draw: Draw) => {
-          draw.config.size = undefined
+          draw.config.size = null
           draw.config.back = { color: "#fff", opacity: 1 };
           delete draw.config.margin
           delete draw.config.border

+ 2 - 14
src/example/fuse/views/slide/test-menu.ts

@@ -1,7 +1,7 @@
 import { v4 as uuid } from "uuid";
 import { Draw } from "../use-draw";
 import { themeColor } from "@/constant/help-style";
-import { tInitData } from '../init'
+import { tInitData } from '../test'
 
 export const testMenus = [
   {
@@ -29,19 +29,7 @@ export const testMenus = [
         icon: "",
         name: "切换指南针显示",
         handler: (draw: Draw) => {
-          const compass = draw.store.items.find((item) => item.key === "compass");
-          if (compass) {
-            draw.delShape(compass.id);
-          } else {
-            draw.addShape("icon", {
-              url: "/icons/edit_compass.svg",
-              width: 100,
-              height: 100,
-              key: "compass",
-              fill: themeColor,
-              fixScreen: { right: 40, top: 40 },
-            });
-          }
+          draw.config.showCompass = !draw.config.showCompass
         }
       },
       {

+ 983 - 0
src/example/fuse/views/test.ts

@@ -0,0 +1,983 @@
+export const initData = {
+  typeItems: {
+    image: [
+      {
+        id: "-10",
+        createTime: 1,
+        zIndex: -194,
+        url: "/WX20241213-205427@2x.png",
+        mat: [
+          0.11196146764392557, 0, 0, 0.11196146764392542, 115.58984375,
+          243.9711189430529,
+        ],
+      },
+      {
+        id: "10cc6b4d-e90a-47c2-ae3f-9ab3a21190e7",
+        createTime: 1736762304345,
+        zIndex: -1,
+        opacity: 1,
+        ref: false,
+        width: 1000,
+        height: 1000,
+        url: "/五楼.png",
+        mat: [1, 0, 0, 1, 591, 436],
+        lock: true,
+      },
+    ],
+    bgImage: [],
+    rectangle: [
+      {
+        id: "0",
+        createTime: 1,
+        zIndex: 0,
+        attitude: [
+          8.251736904074757e-17, 1.347610904600402, -1.476797504076872,
+          -1.5348915434824124e-13, 1569.5827159467738, -794.9590755343082,
+        ],
+        points: [
+          { x: 1363.3800961316804, y: 483.5732802091982 },
+          { x: 1363.380096131679, y: 711.9249144776211 },
+          { x: 1088.6068794194352, y: 711.9249144775904 },
+          { x: 1088.606879419436, y: 483.57328020916987 },
+        ],
+      },
+      {
+        id: "1",
+        createTime: 0,
+        zIndex: 0,
+        attitude: [
+          1.2148907961465611, -1.1842248053033169, 0.9286933259554236,
+          0.952742223514732, -274.21565282732183, 1472.5179431383922,
+        ],
+        fill: "red",
+        points: [
+          { x: 791.8290392640735, y: 704.1094464497272 },
+          { x: 986.4696856698326, y: 514.3818739591983 },
+          { x: 1150.8993397890408, y: 683.0695019402921 },
+          { x: 956.258693383281, y: 872.7970744308196 },
+        ],
+      },
+      {
+        id: "efe1cf7c-74ec-4c62-a23e-f68ced234c6b",
+        createTime: 1736386331805,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -399.703125, y: 420.65234375 },
+          { x: -281.390625, y: 420.65234375 },
+          { x: -281.390625, y: 544.06640625 },
+          { x: -399.703125, y: 544.06640625 },
+        ],
+        attitude: [1, 0, 0, 1, 0, 0],
+        dash: [4.32, 25.68],
+      },
+      {
+        id: "ec71e6ac-7214-484a-aebf-d0ea3bd6cd32",
+        createTime: 1736386333439,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -281.390625, y: 544.06640625 },
+          { x: -154.1640625, y: 544.06640625 },
+          { x: -154.1640625, y: 671.86328125 },
+          { x: -281.390625, y: 671.86328125 },
+        ],
+        attitude: [1, 0, 0, 1, 0, 0],
+      },
+      {
+        id: "f54f8b3b-4f2e-4811-b5c3-f90a2fd9deb2",
+        createTime: 1736386335742,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -281.390625, y: 544.06640625 },
+          { x: -399.703125, y: 544.06640625 },
+          { x: -399.703125, y: 671.86328125 },
+          { x: -281.390625, y: 671.86328125 },
+        ],
+        attitude: [1, 0, 0, 1, 0, 0],
+      },
+      {
+        id: "647b6f0d-6cf3-46ef-be3f-efd7854e66b6",
+        createTime: 1736386338885,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -281.390625, y: 544.06640625 },
+          { x: -154.1640625, y: 544.06640625 },
+          { x: -154.1640625, y: 420.65234375 },
+          { x: -281.390625, y: 420.65234375 },
+        ],
+        attitude: [1, 0, 0, 1, 0, 0],
+        dash: [8.1, 21.9],
+      },
+      {
+        id: "63d8d8d6-9bfc-4756-b4d8-28fd78d75404",
+        createTime: 1736386349032,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -154.1640625, y: 420.65234375 },
+          { x: -399.703125, y: 420.65234375 },
+          { x: -399.703125, y: 357.41015625 },
+          { x: -154.1640625, y: 357.41015625 },
+        ],
+        attitude: [1, 0, 0, 1, 0, 0],
+        dash: [19.81, 10.190000000000001],
+      },
+      {
+        id: "c147512f-b7fa-4638-83e9-b2bbd7311a4a",
+        createTime: 1736386356941,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -154.1640625, y: 671.86328125 },
+          { x: 70.11328125, y: 671.86328125 },
+          { x: 70.11328125, y: 357.41015625 },
+          { x: -154.1640625, y: 357.41015625 },
+        ],
+        attitude: [1, 0, 0, 1, 0, 0],
+      },
+      {
+        id: "27df2ef6-0d23-4620-be4c-c9ab49f6e46a",
+        createTime: 1736386360999,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -154.1640625, y: 357.41015625 },
+          { x: 70.11328125, y: 357.41015625 },
+          { x: 70.11328125, y: 544.06640625 },
+          { x: -154.1640625, y: 544.06640625 },
+        ],
+        attitude: [1, 0, 0, 1, 0, 0],
+        dash: [3.63, 26.37],
+      },
+      {
+        id: "60dbebbb-f670-4279-aa5a-7686c366b121",
+        createTime: 1736386369847,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -154.1640625, y: 544.06640625 },
+          { x: 70.11328125, y: 544.06640625 },
+          { x: 70.11328125, y: 671.86328125 },
+          { x: -154.1640625, y: 671.86328125 },
+        ],
+        attitude: [1, 0, 0, 1, 0, 0],
+        dash: [5.72, 24.28],
+      },
+      {
+        id: "15d1acd3-66cf-4e76-bd92-ba2b8432f655",
+        createTime: 1736386395905,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -399.703125, y: 357.41015625 },
+          { x: -587.9070328715221, y: 357.41015625 },
+          { x: -587.9070328715221, y: 671.86328125 },
+          { x: -399.703125, y: 671.86328125 },
+        ],
+        attitude: [1, 0, 0, 1, 0, 0],
+      },
+      {
+        id: "95ed1359-3650-4363-ac01-54c02e72e943",
+        createTime: 1737625169697,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: 207.06697420440253, y: 85.1184373336713 },
+          { x: 327.6607242044025, y: 85.1184373336713 },
+          { x: 327.6607242044025, y: 182.0949998336713 },
+          { x: 207.06697420440253, y: 182.0949998336713 },
+        ],
+        attitude: [1, 0, 0, 1, -329.5931820455975, -123.4440626663287],
+      },
+    ],
+    triangle: [
+      {
+        ref: false,
+        createTime: 3,
+        zIndex: 0,
+        id: "3",
+        attitude: [1, 0, 0, 1, 0, 0],
+        points: [
+          { x: 115.58984375, y: 626.625 },
+          { x: 229.76953125, y: 495.828125 },
+          { x: 343.94921875, y: 626.625 },
+        ],
+      },
+      {
+        id: "b84daf26-66e0-40eb-a35a-ff143da7839c",
+        createTime: 1736386807568,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -597.0415203321531, y: 81.39090892655346 },
+          { x: -566.6056692947864, y: 8.839100341674886 },
+          { x: -536.1698182574196, y: 81.39090892655346 },
+        ],
+      },
+      {
+        id: "cc755da7-7cdd-44b6-b4a1-e2a9b9abb97c",
+        createTime: 1736386808809,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -505.7339672200528, y: 8.839100341674886 },
+          { x: -536.1698182574196, y: 81.39090892655346 },
+          { x: -566.6056692947864, y: 8.839100341674886 },
+        ],
+      },
+      {
+        id: "4b2505ac-4e61-4c79-9053-7ce9c8ef9f29",
+        createTime: 1736386811452,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -475.29811618268604, y: 81.39090892655346 },
+          { x: -505.7339672200528, y: 8.839100341674886 },
+          { x: -536.1698182574196, y: 81.39090892655346 },
+        ],
+      },
+      {
+        id: "8a18d563-3e1e-4b68-8436-f37a5ee932b4",
+        createTime: 1736386825508,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -444.86226514531927, y: 8.839100341674886 },
+          { x: -475.29811618268604, y: 81.39090892655346 },
+          { x: -505.7339672200528, y: 8.839100341674886 },
+        ],
+      },
+      {
+        id: "e5d5cc39-2277-4b97-9270-ab06812e33cc",
+        createTime: 1736386828089,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: -414.4264141079525, y: 81.39090892655346 },
+          { x: -444.86226514531927, y: 8.839100341674886 },
+          { x: -475.29811618268604, y: 81.39090892655346 },
+        ],
+      },
+    ],
+    polygon: [
+      {
+        createTime: 3,
+        zIndex: 0,
+        id: "33",
+        attitude: [1, 0, 0, 1, -294.60546875, -13.67578125],
+        points: [
+          { x: 121.93359375, y: 341.10546875 },
+          { x: 420.87109375, y: 356.50390625 },
+          { x: 392.12890625, y: 524.4921875 },
+          { x: 105.9609375, y: 517.86328125 },
+          { x: 18.832558784586354, y: 515.8450055612782 },
+          { x: 18.832558784586354, y: 335.79467688514586 },
+        ],
+        dash: [18.42, 11.579999999999998],
+      },
+      {
+        id: "7105a114-964c-4f55-8bc4-911b37fbc768",
+        createTime: 1736845626186,
+        zIndex: 0,
+        opacity: 1,
+        ref: true,
+        points: [
+          { x: 859.33203125, y: 305.10546875 },
+          { x: 859.33203125, y: 380.2421875 },
+          { x: 859.33203125, y: 548.828125 },
+          { x: 601.39453125, y: 548.828125 },
+          { x: 351.71875, y: 548.828125 },
+          { x: 351.71875, y: 424.39453125 },
+          { x: 351.71875, y: 273.09375 },
+          { x: 351.71875, y: 195.64453125 },
+          { x: 859.33203125, y: 195.64453125 },
+        ],
+        attitude: [1, 0, 0, 1, 286.56640625, -2.3671875],
+      },
+      {
+        id: "fbdfc09e-1f81-4772-8c3a-316d50cc7da1",
+        createTime: 1737012759015,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        points: [
+          { x: 1705.741066896583, y: -839.713131499153 },
+          { x: 1938.3695756456666, y: -839.713131499153 },
+          { x: 1938.3695756456666, y: -619.115475249153 },
+          { x: 1705.741066896583, y: -619.115475249153 },
+        ],
+        attitude: [1, 0, 0, 1, 1054.152456203272, -1346.193323532427],
+        strokeWidth: 10,
+        stroke: "#C71585",
+        fill: "#1F93FF",
+        dash: [11.16, 18.84],
+      },
+    ],
+    line: [
+      {
+        createTime: 3,
+        zIndex: 0,
+        id: "333",
+        attitude: [1, 0, 0, 1, 264.050567067064, -209.36399936114208],
+        points: [
+          { x: 691.9908236537299, y: -256.43159647539807 },
+          { x: 834.8596014933705, y: -256.43159647539807 },
+          { x: 834.8596014933705, y: 52.60589610179676 },
+          { x: 668.8302882438311, y: 52.60589610179676 },
+          { x: 668.8302882438311, y: -84.48785389820324 },
+          { x: 569.2892889933705, y: -84.48785389820324 },
+          { x: 569.2892889933705, y: 52.60589610179676 },
+          { x: 471.5666327433705, y: 52.60589610179676 },
+          { x: 471.5666327433705, y: -122.69879139820324 },
+          { x: 569.2892889933705, y: -122.69879139820324 },
+          { x: 569.2892889933705, y: -256.43159647539807 },
+          { x: 471.5666327433705, y: -256.43159647539807 },
+          { x: 471.5666327433705, y: -385.2632664678143 },
+        ],
+        ref: false,
+        dash: [20.66, 9.34],
+        strokeWidth: 10,
+        stroke: "#047E22",
+      },
+    ],
+    arrow: [
+      {
+        id: "8",
+        createTime: 1,
+        zIndex: 0,
+        attitude: [1, 0, 0, 1, -85.9609375, 129.58203125],
+        points: [
+          { x: 879.94140625, y: 265.87109375 },
+          { x: 662.28515625, y: 381.26171875 },
+        ],
+      },
+      {
+        id: "9",
+        createTime: 1,
+        zIndex: 0,
+        attitude: [1, 0, 0, 1, 78.11328125, -42.01171875],
+        points: [
+          { x: 834.46875, y: 52.76953125 },
+          { x: 958.0546875, y: 223.859375 },
+        ],
+      },
+    ],
+    circle: [
+      {
+        id: "335dd470-a6b5-4fef-bb26-0a40010c4b96",
+        createTime: 1737621610324,
+        zIndex: 1,
+        opacity: 1,
+        ref: false,
+        mat: [1, 0, 0, 1, 645.1796875, 139.01171875],
+        radiusX: 277.6712260605102,
+        radiusY: 82.0068317036322,
+      },
+      {
+        id: "5a292b3a-ce0e-47a8-a03b-c2c44c38f97f",
+        createTime: 1738834412964,
+        lock: false,
+        zIndex: 3,
+        opacity: 1,
+        ref: false,
+        mat: [1, 0, 0, 1, -540.352979059887, -785.2716514826207],
+        radiusX: 79.5859375,
+        radiusY: 101.392578125,
+      },
+    ],
+    text: [
+      {
+        createTime: 3,
+        zIndex: 0,
+        id: "333asdt3",
+        fill: "#000",
+        fontFamily: "Calibri",
+        fontSize: 30,
+        content: "我爱人人人人爱我",
+        mat: [
+          -1.4930798945178672e-15, 1.0000000000000104, -1.0000000000000155,
+          -1.5971633030764742e-15, 1083.2463425727433, 95.00094657517106,
+        ],
+        width: 71.86542465603814,
+      },
+      {
+        createTime: 3,
+        zIndex: 0,
+        id: "3t3asd33",
+        fill: "#000",
+        fontFamily: "Calibri",
+        fontSize: 30,
+        width: 300,
+        content: "文字",
+        mat: [1, 0, 0, 1, 873.94921875, 659.453125],
+      },
+    ],
+    table: [
+      {
+        stroke: "#d8000a",
+        strokeWidth: 1,
+        id: "95b321a0-f36b-41e9-a102-96c04b2b4d39",
+        createTime: 1737885095135,
+        lock: false,
+        zIndex: 2,
+        opacity: 1,
+        ref: true,
+        width: 232.73828125,
+        height: 224.91796875,
+        content: [
+          [
+            {
+              content: "qwe",
+              width: 116.369140625,
+              height: 56.2294921875,
+              align: "center",
+              fontStyle: "italic",
+            },
+            {
+              content: "czx",
+              width: 116.369140625,
+              height: 56.2294921875,
+              align: "center",
+              fontStyle: "italic",
+            },
+          ],
+          [
+            {
+              content: "1231",
+              width: 116.369140625,
+              height: 56.2294921875,
+              align: "center",
+              fontStyle: "italic",
+            },
+            {
+              content: "5324",
+              width: 116.369140625,
+              height: 56.2294921875,
+              align: "center",
+              fontStyle: "italic",
+            },
+          ],
+          [
+            {
+              content: "asd",
+              width: 116.369140625,
+              height: 56.2294921875,
+              align: "center",
+              fontStyle: "italic",
+            },
+            {
+              content: "qe",
+              width: 116.369140625,
+              height: 56.2294921875,
+              align: "center",
+              fontStyle: "italic",
+            },
+          ],
+          [
+            {
+              content: "123",
+              width: 116.369140625,
+              height: 56.2294921875,
+              align: "center",
+              fontStyle: "italic",
+            },
+            {
+              content: "zxc",
+              width: 116.369140625,
+              height: 56.2294921875,
+              align: "center",
+              fontStyle: "italic",
+            },
+          ],
+        ],
+        mat: [1, 0, 0, 1, 1867.804575999732, 828.8137443432463],
+        align: "center",
+        fontStyle: "italic",
+        fill: "",
+      },
+      {
+        stroke: "#d8000a",
+        strokeWidth: 1,
+        fontSize: 16,
+        align: "center",
+        fontStyle: "normal",
+        fontColor: "#d8000a",
+        id: "de4475a7-95ef-4438-98ab-d6f0045f7f61",
+        createTime: 1738913187767,
+        lock: false,
+        zIndex: 4,
+        opacity: 1,
+        ref: false,
+        width: 425.8472387828342,
+        height: 262.0582582259674,
+        content: [
+          [
+            {
+              content: "1234",
+              width: 106.46180969570855,
+              height: 99.70181998577598,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "请问请问",
+              width: 106.46180969570855,
+              height: 99.70181998577598,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content:
+                "按时打算自行车按时按时打算自行车按时按时打算自行车按时按时打算自行车按时",
+              width: 106.46180969570855,
+              height: 99.70181998577598,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "亲请问请问请问",
+              width: 106.46180969570855,
+              height: 99.70181998577598,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+          ],
+          [
+            {
+              content: "45234",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "123asdasdasdasdasdasd按时打算大叔大婶大叔大婶的",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "asdasd",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "自行车这些",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+          ],
+          [
+            {
+              content: "65345",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "123123",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "123123",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "43214",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+          ],
+          [
+            {
+              content: "5423234",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "123123",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "43224",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "123123",
+              width: 106.46180969570855,
+              height: 54.11881274673046,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+          ],
+        ],
+        mat: [1, 0, 0, 1, 416.91799465370843, 869.4103464598702],
+      },
+    ],
+  },
+  config: {
+    drawSize: null,
+    compass: { rotation: 0 },
+    proportion: {scale: 1}
+  }
+};
+
+export const tInitData = {
+  typeItems: {
+    serial: [
+      {
+        fontSize: 16,
+        id: "bb74bd30-2307-4b21-8187-d46970143c13",
+        createTime: 1740044984050,
+        lock: false,
+        zIndex: 1,
+        opacity: 1,
+        ref: false,
+        content: "1",
+        padding: 3,
+        mat: [1, 0, 0, 1, 147.109375, 193.734375],
+        radiusX: 11.030865786510143,
+        radiusY: 11.030865786510143,
+      },
+      {
+        fontSize: 16.000000000000004,
+        id: "d152d5cb-78e0-4dd0-b719-dd826d5f26e2",
+        createTime: 1740044984390,
+        lock: false,
+        zIndex: 1,
+        opacity: 1,
+        ref: false,
+        content: "2",
+        padding: 3,
+        mat: [1, 0, 0, 1, 718.1640625, 241.56640625],
+        radiusX: 11.030865786510143,
+        radiusY: 11.030865786510143,
+      },
+      {
+        fontSize: 16,
+        id: "9800c6d2-8bf8-4498-8add-174ecb6be7ba",
+        createTime: 1740044984918,
+        lock: false,
+        zIndex: 1,
+        opacity: 1,
+        ref: false,
+        content: "3",
+        padding: 3,
+        mat: [1, 0, 0, 1, 592.4601690730203, 529.20703125],
+        radiusX: 11.030865786510143,
+        radiusY: 11.030865786510143,
+      },
+      {
+        fontSize: 16,
+        id: "ade6a69a-9f19-4905-9d80-555b9dd8e2ba",
+        createTime: 1740044985418,
+        lock: false,
+        zIndex: 1,
+        opacity: 1,
+        ref: false,
+        content: "4",
+        padding: 3,
+        mat: [1, 0, 0, 1, 285.88671875, 565.828125],
+        radiusX: 11.030865786510143,
+        radiusY: 11.030865786510143,
+      },
+      {
+        fontSize: 16,
+        id: "9a8e3fed-fc1d-4979-83d4-9bef8e994510",
+        createTime: 1740044985856,
+        lock: false,
+        zIndex: 1,
+        opacity: 1,
+        ref: false,
+        content: "5",
+        padding: 3,
+        mat: [1, 0, 0, 1, 899.28125, 370.48828125],
+        radiusX: 11.030865786510143,
+        radiusY: 11.030865786510143,
+      },
+      {
+        fontSize: 16,
+        id: "4e7c431a-b5e4-4907-bdfb-ca6031c90fe0",
+        createTime: 1740044986325,
+        lock: false,
+        zIndex: 1,
+        opacity: 1,
+        ref: false,
+        content: "6",
+        padding: 3,
+        mat: [1, 0, 0, 1, 718.6328125, 136.68359375],
+        radiusX: 11.030865786510143,
+        radiusY: 11.030865786510143,
+      },
+    ],
+    table: [
+      {
+        stroke: "#d8000a",
+        strokeWidth: 1,
+        fontSize: 16,
+        align: "center",
+        fontStyle: "normal",
+        fontColor: "#d8000a",
+        id: "3822a4f6-3b84-4d5c-9507-6c71cac1e3df",
+        createTime: 1740044984356,
+        lock: false,
+        zIndex: 0,
+        opacity: 1,
+        ref: false,
+        notaddRow: true,
+        notaddCol: true,
+        key: "serial-table",
+        content: [
+          [
+            {
+              content: "序号",
+              readonly: true,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32.00000000000003,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "描述",
+              readonly: true,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32.00000000000003,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+          ],
+          [
+            {
+              content: "1",
+              readonly: true,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "1",
+              readonly: false,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+          ],
+          [
+            {
+              content: "2",
+              readonly: true,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "2",
+              readonly: false,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+          ],
+          [
+            {
+              content: "3",
+              readonly: true,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32.00000000000003,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "3",
+              readonly: false,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32.00000000000003,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+          ],
+          [
+            {
+              content: "4",
+              readonly: true,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32.00000000000003,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "4",
+              readonly: false,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32.00000000000003,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+          ],
+          [
+            {
+              content: "5",
+              readonly: true,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32.00000000000003,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "5",
+              readonly: false,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32.00000000000003,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+          ],
+          [
+            {
+              content: "6",
+              readonly: true,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32.00000000000003,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+            {
+              content: "6",
+              readonly: false,
+              notdel: true,
+              width: 107.00000000000001,
+              height: 32.00000000000003,
+              padding: 8,
+              fontColor: "#d8000a",
+              fontStyle: "normal",
+              align: "center",
+            },
+          ],
+        ],
+        width: 214.00000000000003,
+        height: 224.00000000000014,
+        mat: [1, 0, 0, 1, 389.31602203651016, 223.13633453651013],
+      },
+    ]
+  },
+  config: {
+    drawSize: null,
+    proportion: {scale: 1},
+    compass: { rotation: 0 },
+  }
+};

+ 10 - 23
src/example/fuse/views/use-draw.ts

@@ -1,39 +1,26 @@
 import { inject, provide, Ref, ShallowUnwrapRef, watch } from "vue";
 import { DrawExpose } from "../../../index";
-import { themeColor } from "@/constant/help-style";
 import { mergeFuns } from "@/utils/shared";
 
 const initDraw = (draw: Draw) => {
   draw.config.showLabelLine = false;
   draw.config.showGrid = false;
-	draw.config.back = { color: "#fff", opacity: 1 };
+  draw.config.showCompass = true
 
-  const compass = draw.store.items.find((item) => item.key === "compass");
-  if (!compass) {
-		console.log('add')
-    draw.history.preventTrack(() => {
-      draw.addShape("icon", {
-        url: "/icons/edit_compass.svg",
-        width: 100,
-        height: 100,
-        key: "compass",
-        fill: themeColor,
-        fixScreen: { right: 40, top: 40 },
-      });
-    });
-  }
-  return mergeFuns([
-	])
+  return mergeFuns([]);
 };
 
 const actionKey = Symbol("drawAction");
 export type Draw = ShallowUnwrapRef<DrawExpose>;
 export const installDraw = (drawRef: Ref<DrawExpose | undefined>) => {
-  watch(() => drawRef?.value?.stage, (_a, _b, onCleanup) => {
-		if (drawRef.value) {
-    	onCleanup(initDraw(drawRef.value as unknown as Draw));
-		}
-  });
+  watch(
+    () => drawRef?.value?.stage,
+    (_a, _b, onCleanup) => {
+      if (drawRef.value) {
+        onCleanup(initDraw(drawRef.value as unknown as Draw));
+      }
+    }
+  );
   provide(actionKey, drawRef);
 };
 

+ 3 - 3
src/utils/bound.ts

@@ -1,4 +1,4 @@
-import { Pos } from "./math";
+import { Pos, Size } from "./math";
 
 export type FixScreen = {
   left?: number;
@@ -8,8 +8,8 @@ export type FixScreen = {
 };
 export const getFixPosition = (
   pos: FixScreen,
-  selfSize: { width: number; height: number },
-  screenSize: { width: number; height: number }
+  selfSize: Size,
+  screenSize: Size
 ) => {
   let x = pos.left;
   let y = pos.top;

+ 1 - 0
src/utils/math.ts

@@ -3,6 +3,7 @@ import { Transform } from "konva/lib/Util";
 import { round } from "./shared.ts";
 
 export type Pos = { x: number; y: number };
+export type Size = { width: number, height: number }
 
 export const vector = (pos: Pos = { x: 0, y: 0 }): Vector2 => {
   return new Vector2(pos.x, pos.y);

+ 2 - 5
src/utils/resource.ts

@@ -1,4 +1,5 @@
 import { reactive } from "vue";
+import { Pos, Size } from "./math";
 
 let imageCache: Record<string, Promise<HTMLImageElement>>;
 export let imageInfo: Record<string, Record<'width' | 'height', number>> = reactive({})
@@ -57,12 +58,8 @@ export type SVGPath = {
   strokeWidth?: number;
   data: string;
 };
-export type SVGParseResult = {
+export type SVGParseResult = Size & Pos & {
   paths: SVGPath[];
-  width: number;
-  height: number;
-  x: number;
-  y: number;
 };
 let svgParseCache: Record<string, SVGParseResult>;
 let helpDOM: HTMLDivElement;