import { AnimationModel, AnimationModelAction, AnimationModelFrame, AnimationModelPath, } from "@/api"; import { AnimationGroup, AnimationModel3D, AnimationModelAction3D, AnimationModelFrame3D, AnimationModelPath3D, SDK, sdk as _sdk, } from "../sdk"; import { computed, nextTick, reactive, watch, watchEffect } from "vue"; import { ams } from "@/store/animation"; import { mergeFuns } from "@/components/drawing/hook"; import { getPathNode } from "./path"; export let animationGroup: AnimationGroup; const getAMKey = (am: AnimationModel) => am.key || am.id; const amMap: Record< string, { am?: AnimationModel3D; frames: Record; actions: Record; paths: Record; } > = reactive({}); export const addAM = (data: AnimationModel): Promise => { const key = getAMKey(data); const stopLoad = watch( () => { const exixts = ams.value.some((am) => getAMKey(am) === key); return [key, exixts] as const; }, ([key, exixts]) => { if (!exixts) { const des = amMap[key]; if (!des) return; Object.values(des.frames || {}).forEach((frame) => frame.destory()); Object.values(des.actions || {}).forEach((frame) => frame.destory()); Object.values(des.paths || {}).forEach((frame) => frame.destory()); des.am?.destory(); delete amMap[key]; } else if (!amMap[key]) { amMap[key] = { frames: {}, actions: {}, paths: {}, }; animationGroup .addAnimationModel(data) .then((am) => (amMap[key].am = am)); } }, { immediate: true } ); const stopAttrib = mergeFuns( () => watchEffect(() => amMap[key].am?.changeVisibilityRange( data.globalVisibility ? undefined : data.visibilityRange ) ), watchEffect(() => amMap[key].am?.changeTitle(data.title)), watchEffect(() => amMap[key].am?.visibilityTitle(data.showTitle)), watchEffect(() => amMap[key].am?.changeFontSize(data.fontSize)) ); const stopWatch = watch( () => ams.value.includes(data), (exists) => { if (!exists) { stopLoad(); stopAttrib(); stopWatch(); } }, { flush: "post" } ); return new Promise((resolve) => { const stopWatch = watchEffect(() => { if (amMap[key]?.am) { resolve(amMap[key]!.am!); nextTick(() => stopWatch()); } }); }); }; export const addFrame = ( data: AnimationModelFrame ): Promise => { const am = ams.value.find((item) => item.frames.find(({ id }) => id === data.id) ); if (!am) { throw "找不到am数据"; } const key = getAMKey(am); const stopLoad = watch( () => { const exists = am.frames.some(({ id }) => id === data.id); return [amMap[key], exists] as const; }, ([map, exists]) => { if (!map.am) return; if (exists && !map.frames[data.id]) { map.frames[data.id] = map.am.addFrame(data); } else if (!exists && map.frames[data.id]) { map.frames[data.id].destory(); delete map.frames[data.id]; } } ); const stopAttrib = mergeFuns(() => watchEffect(() => amMap[key].frames[data.id]?.changeTime(data.time)) ); const stopWatch = watch( () => am.frames.includes(data), (exists) => { if (!exists) { stopLoad(); stopAttrib(); stopWatch(); } }, { flush: "post" } ); return new Promise((resolve) => { const stopWatch = watchEffect(() => { if (amMap[key]?.frames[data.id]) { resolve(amMap[key].frames[data.id]); nextTick(() => stopWatch()); } }); }); }; export const addAction = ( data: AnimationModelAction ): Promise => { const am = ams.value.find((item) => item.actions.find(({ id }) => id === data.id) ); if (!am) { throw "找不到am数据"; } const key = getAMKey(am); const stopLoad = watch( () => { const exists = am.actions.some(({ id }) => id === data.id); return [amMap[key], exists] as const; }, ([map, exists]) => { if (!map.am) return; if (exists && !map.actions[data.id]) { map.actions[data.id] = map.am.addAction(data); } else if (!exists && map.actions[data.id]) { map.actions[data.id].destory(); delete map.actions[data.id]; } } ); const stopAttrib = mergeFuns( () => watchEffect(() => amMap[key].actions[data.id]?.changeTime(data.time)), () => watchEffect(() => amMap[key].actions[data.id]?.changeAmplitude(data.amplitude)), () => watchEffect(() => amMap[key].actions[data.id]?.changeSpeed(data.speed)), () => watchEffect(() => amMap[key].actions[data.id]?.changeDuration(data.duration)), ); const stopWatch = watch( () => am.actions.includes(data), (exists) => { if (!exists) { stopLoad(); stopAttrib(); stopWatch(); } }, { flush: "post" } ); return new Promise((resolve) => { const stopWatch = watchEffect(() => { if (amMap[key]?.actions[data.id]) { resolve(amMap[key].actions[data.id]); nextTick(() => stopWatch()); } }); }); }; export const addPath = ( data: AnimationModelPath ): Promise => { const am = ams.value.find((item) => item.paths.find(({ id }) => id === data.id) ); if (!am) { throw "找不到am数据"; } const path = computed(() => data.pathId ? getPathNode(data.pathId) : undefined) const key = getAMKey(am); const stopLoad = watch( () => { const exists = am.paths.some(({ id }) => id === data.id); return [amMap[key], exists, path.value] as const; }, ([map, exists, path]) => { if (!map.am || !path) return; if (exists && !map.paths[data.id]) { map.paths[data.id] = map.am.addPath({...data, path}); } else if (!exists && map.paths[data.id]) { map.paths[data.id].destory(); delete map.paths[data.id]; } } ); const stopAttrib = mergeFuns( () => watchEffect(() => amMap[key].paths[data.id]?.changeTime(data.time)), () => watchEffect(() => amMap[key].paths[data.id]?.changeReverse(data.reverse)), () => watchEffect(() => amMap[key].paths[data.id]?.changeDuration(data.duration)), () => watchEffect(() => amMap[key].paths[data.id]?.changePath(path.value)), ); const stopWatch = watch( () => am.paths.includes(data), (exists) => { if (!exists) { stopLoad(); stopAttrib(); stopWatch(); } }, { flush: "post" } ); return new Promise((resolve) => { const stopWatch = watchEffect(() => { if (amMap[key]?.paths[data.id]) { resolve(amMap[key].paths[data.id]); nextTick(() => stopWatch()); } }); }); }; export const associationAnimation = (sdk: SDK, el: HTMLDivElement) => { animationGroup = sdk.createAnimationGroup(); };