import { DC, EntityShape } from "@/deconstruction"; import { computed, EmitFn, isRef, reactive, Ref, ref, shallowReactive, watchEffect, } from "vue"; import { useAutomaticData } from "./use-automatic-data"; import { useCurrentZIndex, useZIndex } from "./use-layer"; import { useAnimationMouseStyle } from "./use-mouse-status"; import { components, DrawItem, ShapeType } from "../components"; import { useMatCompTransformer, useLineTransformer } from "./use-transformer"; import { useGetShapeCopyTransform } from "./use-copy"; import { Bottom, Delete, DocumentCopy, Location, Lock, Top, Unlock, } from "@element-plus/icons-vue"; import { mergeFuns, onlyId } from "@/utils/shared"; import { Shape } from "konva/lib/Shape"; import { Transform } from "konva/lib/Util"; import { mergeDescribes, PropertyKeys } from "../propertys"; import { useStore } from "../store"; import { globalWatch } from "./use-global-vars"; import { useAlignmentShape } from "./use-alignment"; type Emit = EmitFn<{ updateShape: (value: T) => void; addShape: (value: T) => void; delShape: () => void; }>; export const useComponentMenus = ( shape: Ref | undefined>, data: Ref, emit: Emit, alignment?: (data: T, mat: Transform) => void, copyHandler?: (transform: Transform, data: T) => T ) => { const operateMenus: Array<{ icon?: any; label?: string; handler: () => void; }> = shallowReactive([]); // 锁定 解锁 operateMenus.push( reactive({ label: computed(() => (data.value.lock ? "解锁" : "锁定")) as any, icon: computed(() => (data.value.lock ? Unlock : Lock)), handler() { data.value.lock = !data.value.lock; emit("updateShape", { ...data.value }); }, }) ); // 置顶 置底 const currentZIndex = useCurrentZIndex(); operateMenus.push( { label: `置顶`, icon: Top, handler() { data.value.zIndex = currentZIndex.max + 1; emit("updateShape", { ...data.value }); }, }, { label: `置底`, icon: Bottom, handler() { data.value.zIndex = currentZIndex.min - 1; emit("updateShape", { ...data.value }); }, } ); if (alignment) { const [alignmentShape] = useAlignmentShape(shape); operateMenus.push({ label: "对齐", async handler() { const mat = await alignmentShape(); alignment(data.value, mat); emit("updateShape", { ...data.value }); }, icon: Location, }); } if (copyHandler) { const getCopyTransform = useGetShapeCopyTransform(shape); operateMenus.push({ label: `复制`, icon: DocumentCopy, handler() { const transform = getCopyTransform(); const copyData = copyHandler( transform, JSON.parse(JSON.stringify(data.value)) as T ); copyData.id = onlyId(); emit("addShape", copyData); }, }); } operateMenus.push({ label: `删除`, icon: Delete, handler() { emit("delShape"); }, }); return operateMenus; }; export type UseComponentStatusProps< T extends DrawItem, S extends EntityShape > = { emit: Emit; type?: ShapeType; props: { data: T }; alignment?: (data: T, mat: Transform) => void; getMouseStyle: any; defaultStyle: any; propertys: PropertyKeys; transformType?: "line" | "mat" | "custom"; customTransform?: ( callback: () => void, shape: Ref | undefined>, data: Ref ) => void; getRepShape?: () => Shape; copyHandler: (transform: Transform, data: T) => T; }; export const useComponentStatus = ( args: UseComponentStatusProps ) => { const shape = ref>(); const data = useAutomaticData(() => args.props.data); const [style] = useAnimationMouseStyle({ data: data, shape, getMouseStyle: args.getMouseStyle, }) as any; if (args.transformType === "line") { useLineTransformer( shape as any, data as any, (newData) => args.emit("updateShape", newData as T), args.getRepShape as any ); } else if (args.transformType === "mat") { useMatCompTransformer(shape, data as any, (nData) => args.emit("updateShape", nData as any) ); } else if (args.transformType === "custom" && args.customTransform) { args.customTransform( () => args.emit("updateShape", data.value as any), shape, data ); } useZIndex(shape, data); return { data, style, tData: computed(() => { const tData = { ...args.defaultStyle, ...data.value }; if (style) { Object.assign(tData, style.value); } return tData; }), shape, operateMenus: useComponentMenus( shape, data, args.emit, args.alignment, args.copyHandler ), describes: mergeDescribes( data, args.defaultStyle, args.propertys || [] ) }; }; export const useGetComponentData = () => { const store = useStore(); return (shape: Ref | EntityShape | undefined) => computed(() => { shape = isRef(shape) ? shape.value : shape; if (!shape?.id()) return; return store.getItemById(shape.id()) as D; }); }; export const useComponentsAttach = ( getter: (type: K, data: DrawItem) => T, types = Object.keys(components) as ShapeType[] ) => { const store = useStore(); const attachs = reactive([]) as T[]; const cleanups = [] as Array<() => void>; for (const type of types) { cleanups.push( globalWatch( () => store.data[type]?.map((item) => item), (items, _, onCleanup) => { if (!items) return; for (const item of items) { const attachWatchStop = watchEffect((onCleanup) => { const attach = getter(type, item); attachs.push(attach); onCleanup(() => { const ndx = attachs.indexOf(attach); ~ndx && attachs.splice(ndx, 1); }); }); const existsWatchStop = watchEffect(() => { if (!items.includes(item)) { attachWatchStop(); existsWatchStop(); } }); onCleanup(() => { attachWatchStop(); existsWatchStop(); }); } }, { immediate: true } ) ); } return { attachs, cleanup: mergeFuns(cleanups), }; };