| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- import { DC, EntityShape } from "@/deconstruction";
- import {
- computed,
- EmitFn,
- isRef,
- markRaw,
- nextTick,
- onUnmounted,
- reactive,
- ref,
- Ref,
- shallowReactive,
- shallowRef,
- watch,
- watchEffect,
- } from "vue";
- import { useAutomaticData } from "./use-automatic-data";
- import { useCurrentZIndex, useZIndex } from "./use-layer";
- import {
- useAnimationMouseStyle,
- useMouseShapesStatus,
- } from "./use-mouse-status";
- import { components, DrawItem, ShapeType } from "../components";
- import { useMatCompTransformer, useLineTransformer } from "./use-transformer";
- import { useGetShapeCopyTransform } from "./use-copy";
- import { asyncTimeout, copy, mergeFuns, onlyId } from "@/utils/shared";
- import { Shape } from "konva/lib/Shape";
- import { Transform } from "konva/lib/Util";
- import {
- mergeDescribes,
- PropertyDescribes,
- PropertyKeys,
- } from "../html-mount/propertys";
- import { useStore } from "../store";
- import { globalWatch, useMountMenusFilter, useStage } from "./use-global-vars";
- import { useAlignmentShape } from "./use-alignment";
- import { useViewerTransform } from "./use-viewer";
- import { usePause } from "./use-pause";
- import { useGlobalDescribes } from "./use-group";
- import { ui18n } from "@/lang";
- type Emit<T> = EmitFn<{
- updateShape: (value: T) => void;
- addShape: (value: T) => void;
- delShape: () => void;
- }>;
- export const useComponentMenus = <T extends DrawItem>(
- shape: Ref<DC<EntityShape> | undefined>,
- data: Ref<T>,
- emit: Emit<T>,
- alignment?: (data: T, mat: Transform) => void,
- copyHandler?: (transform: Transform, data: T) => T
- ) => {
- const operateMenus: Array<{
- icon?: any;
- label?: string;
- hide?: boolean,
- handler: () => void;
- }> = shallowReactive([]);
- // 置顶 置底
- const currentZIndex = useCurrentZIndex();
- operateMenus.push(
- reactive({
- label: computed(() => (data.value.lock ? ui18n.t('sys.unlock') : ui18n.t('sys.lock'))) as any,
- handler() {
- data.value.lock = !data.value.lock;
- emit("updateShape", { ...data.value });
- },
- }),
- reactive({
- label: ui18n.t('sys.hide'),
- hide: true,
- handler() {
- data.value.hide = true;
- emit("updateShape", { ...data.value });
- },
- })
- // {
- // label: `上移`,
- // icon: Top,
- // handler() {
- // data.value.zIndex += 1;
- // emit("updateShape", { ...data.value });
- // },
- // },
- // {
- // label: `下移`,
- // icon: Bottom,
- // handler() {
- // data.value.zIndex -= 1;
- // emit("updateShape", { ...data.value });
- // },
- // },
- );
- if (alignment) {
- const [alignmentShape] = useAlignmentShape(shape);
- operateMenus.push({
- label: ui18n.t('sys.alignment'),
- async handler() {
- const mat = await alignmentShape();
- alignment(data.value, mat);
- emit("updateShape", copy({ ...data.value }));
- // let ndata = { ...data.value, id: onlyId() }
- // emit('addShape', ndata)
- // emit('delShape')
- },
- });
- }
- if (copyHandler) {
- const getCopyTransform = useGetShapeCopyTransform(shape);
- const status = useMouseShapesStatus();
- const stage = useStage();
- operateMenus.push({
- label: ui18n.t('sys.copy'),
- async handler() {
- const transform = getCopyTransform();
- const copyData = copyHandler(
- transform,
- JSON.parse(JSON.stringify(data.value)) as T
- );
- copyData.id = onlyId();
- emit("addShape", copyData);
- status.actives = [];
- await asyncTimeout(100);
- const $stage = stage.value?.getNode();
- if (!$stage) return;
- const $shape = $stage.findOne<Shape>(`#${copyData.id}`);
- if ($shape) {
- status.actives = [$shape];
- }
- },
- });
- }
- operateMenus.push(
- {
- label: ui18n.t('sys.ztop'),
- handler() {
- data.value.zIndex = currentZIndex.max + 1;
- emit("updateShape", { ...data.value });
- },
- },
- {
- label: ui18n.t('sys.zbot'),
- handler() {
- data.value.zIndex = currentZIndex.min - 1;
- emit("updateShape", { ...data.value });
- },
- }
- );
- if (!data.value.disableDelete) {
- operateMenus.push({
- label: ui18n.t('sys.del'),
- handler() {
- emit("delShape");
- },
- });
- }
- return operateMenus;
- };
- export type UseComponentStatusProps<
- T extends DrawItem,
- S extends EntityShape
- > = {
- emit: Emit<T>;
- type?: ShapeType;
- props: { data: T };
- alignment?: (data: T, mat: Transform) => void;
- getMouseStyle: any;
- defaultStyle: any;
- propertys: PropertyKeys;
- selfData?: boolean;
- debug?: boolean;
- noJoinZindex?: boolean;
- noOperateMenus?: boolean;
- transformType?: "line" | "mat" | "custom";
- customTransform?: (
- callback: () => void,
- shape: Ref<DC<S> | undefined>,
- data: Ref<T>
- ) => void;
- getRepShape?: () => Shape;
- copyHandler?: (transform: Transform, data: T) => T;
- };
- export const useComponentDescribes = <T extends { id: string }>(
- data: Ref<T>,
- propertys: PropertyKeys,
- defaultStyle: any
- ) => {
- const store = useStore();
- const id = computed(() => data.value.id);
- const type = computed(() => id.value && store.getType(id.value));
- const initDescs = mergeDescribes(data, defaultStyle, propertys || []);
- const { getFilter } = useMountMenusFilter();
- const gdescs = useGlobalDescribes();
- let descs = ref(initDescs);
- watchEffect(() => {
- const iDescs =
- type.value && id.value
- ? getFilter(type.value, id.value)(initDescs)
- : initDescs;
- descs.value = Object.fromEntries(
- Object.entries(iDescs).sort(
- ([_a, a], [_b, b]) => (b.sort || -1) - (a.sort || -1)
- )
- ) as PropertyDescribes;
- });
- watchEffect((onCleanup) => {
- gdescs.set(data.value, descs.value);
- onCleanup(() => {
- gdescs.del(data.value.id);
- });
- });
- watch(
- descs,
- (descs) => {
- for (const key in descs) {
- const initProps = descs[key].props;
- watchEffect(() => {
- if (!type.value) return;
- const getPredefine = components[type.value].getPredefine;
- const predefine =
- getPredefine && (getPredefine as any)(key as keyof DrawItem);
- if (!predefine) return;
- if (initProps) {
- descs[key].props = { ...initProps, ...predefine };
- } else {
- descs[key].props = predefine;
- }
- });
- }
- },
- { immediate: true }
- );
- return descs;
- };
- export const useComponentStatus = <S extends EntityShape, T extends DrawItem>(
- args: UseComponentStatusProps<T, S>
- ) => {
- const shape = shallowRef<DC<S>>();
- watchEffect(
- () => {
- if (shape.value) {
- markRaw(shape.value);
- }
- },
- { flush: "sync" }
- );
- const data = useAutomaticData(
- () => args.props.data,
- (data) => (args.selfData ? data : copy(data))
- );
- const [style, pause, resume] = useAnimationMouseStyle({
- data: data,
- shape,
- getMouseStyle: args.getMouseStyle,
- }) as any;
- watchEffect(() => {
- if (data.value.lock) {
- pause();
- } else {
- resume();
- }
- });
- 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
- );
- }
- if (!args.noJoinZindex) {
- 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: args.noOperateMenus
- ? []
- : useComponentMenus(
- shape,
- data,
- args.emit,
- args.alignment,
- args.copyHandler
- ),
- describes: useComponentDescribes(
- data,
- args.propertys || [],
- args.defaultStyle
- ),
- };
- };
- export const useGetShapeBelong = () => {
- const store = useStore();
- return (shape: EntityShape) => {
- let curId = shape.id();
- let id: string;
- let item: DrawItem;
- let type: ShapeType;
- do {
- id = shape.id();
- item = store.getItemById(id)!;
- type = store.getType(id)!;
- if (item && type) {
- break;
- }
- } while ((shape = shape.parent as any));
- return item ? { item, isSelf: curId === id, type, id, curId } : null;
- };
- };
- export const useGetComponentData = () => {
- const store = useStore();
- const getShapeBelong = useGetShapeBelong();
- return (shape: Ref<EntityShape | undefined> | EntityShape | undefined) =>
- computed(() => {
- shape = isRef(shape) ? shape.value : shape;
- if (!shape?.id()) return;
- let item: any = store.getItemById(shape.id());
- if (!item) {
- const belong = getShapeBelong(shape);
- if (belong && !belong.isSelf) {
- const getter = components[belong.type].childrenDataGetter;
- let parent: any;
- if (getter && (parent = store.getItemById(belong.id))) {
- item = getter(parent, belong.curId);
- }
- }
- }
- return item;
- });
- };
- export const useComponentsAttach = <T>(
- getter: <K extends ShapeType>(type: K, data: DrawItem<K>) => 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.getTypeItems(type),
- (_a, _, onCleanup) => {
- const items = store.getTypeItems(type);
- 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, deep: true }
- )
- );
- }
- return {
- attachs,
- cleanup: mergeFuns(cleanups),
- };
- };
- export const useOnComponentBoundChange = () => {
- const getComponentData = useGetComponentData();
- const transform = useViewerTransform();
- const quitHooks = [] as Array<() => void>;
- const destory = () => mergeFuns(quitHooks)();
- const on = <T extends EntityShape>(
- shapes: Ref<T | T[] | undefined> | T | T[] | undefined,
- callback: (shape: T, type: "transform" | "data") => void,
- viewListener = true
- ) => {
- const $shapes = computed(() => {
- shapes = isRef(shapes) ? shapes.value : shapes;
- if (!shapes) return [];
- return Array.isArray(shapes) ? shapes : [shapes];
- });
- const update = ($shape: T, type?: "transform" | "data") => {
- if (api.isPause) return;
- callback($shape, type || "data");
- };
- const shapeListener = (shape: T) => {
- const repShape = (shape.repShape as T) || shape;
- const syncBd = () => update(repShape);
- repShape.on("transform", syncBd);
- shape.on("bound-change", syncBd);
- return () => {
- repShape.off("transform", syncBd);
- shape.off("bound-change", syncBd);
- };
- };
- const cleanups: (() => void)[] = [];
- if (viewListener) {
- cleanups.push(
- watch(transform, () =>
- $shapes.value.forEach(($shape) => update($shape, "transform"))
- )
- );
- }
- cleanups.push(
- watch(
- $shapes,
- ($shapes, _, onCleanup) => {
- const cleanups = $shapes.flatMap(($shape) => {
- let item = getComponentData($shape);
- return [
- watch(item, () => nextTick(() => update($shape, "data")), {
- deep: true,
- }),
- shapeListener($shape),
- ];
- });
- onCleanup(mergeFuns(cleanups));
- },
- { immediate: true }
- )
- );
- const onDestroy = mergeFuns(cleanups);
- quitHooks.push(onDestroy);
- return () => {
- const ndx = quitHooks.indexOf(onDestroy);
- ~ndx && quitHooks.splice(ndx, 1);
- onDestroy();
- };
- };
- const api = usePause({ destory, on });
- onUnmounted(destory);
- return api;
- };
|