animation.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import {
  2. AnimationModel,
  3. AnimationModelAction,
  4. AnimationModelFrame,
  5. AnimationModelPath,
  6. } from "@/api";
  7. import {
  8. AnimationGroup,
  9. AnimationModel3D,
  10. AnimationModelAction3D,
  11. AnimationModelFrame3D,
  12. AnimationModelPath3D,
  13. SDK,
  14. sdk as _sdk,
  15. } from "../sdk";
  16. import { computed, nextTick, reactive, watch, watchEffect } from "vue";
  17. import { ams } from "@/store/animation";
  18. import { mergeFuns } from "@/components/drawing/hook";
  19. import { getPathNode } from "./path";
  20. export let animationGroup: AnimationGroup;
  21. const getAMKey = (am: AnimationModel) => am.key || am.id;
  22. const amMap: Record<
  23. string,
  24. {
  25. am?: AnimationModel3D;
  26. frames: Record<string, AnimationModelFrame3D>;
  27. actions: Record<string, AnimationModelAction3D>;
  28. paths: Record<string, AnimationModelPath3D>;
  29. }
  30. > = reactive({});
  31. export const addAM = (data: AnimationModel): Promise<AnimationModel3D> => {
  32. const key = getAMKey(data);
  33. const stopLoad = watch(
  34. () => {
  35. const exixts = ams.value.some((am) => getAMKey(am) === key);
  36. return [key, exixts] as const;
  37. },
  38. ([key, exixts]) => {
  39. if (!exixts) {
  40. const des = amMap[key];
  41. if (!des) return;
  42. Object.values(des.frames || {}).forEach((frame) => frame.destory());
  43. Object.values(des.actions || {}).forEach((frame) => frame.destory());
  44. Object.values(des.paths || {}).forEach((frame) => frame.destory());
  45. des.am?.destory();
  46. delete amMap[key];
  47. } else if (!amMap[key]) {
  48. amMap[key] = {
  49. frames: {},
  50. actions: {},
  51. paths: {},
  52. };
  53. animationGroup
  54. .addAnimationModel(data)
  55. .then((am) => (amMap[key].am = am));
  56. }
  57. },
  58. { immediate: true }
  59. );
  60. const stopAttrib = mergeFuns(
  61. () =>
  62. watchEffect(() =>
  63. amMap[key].am?.changeVisibilityRange(
  64. data.globalVisibility ? undefined : data.visibilityRange
  65. )
  66. ),
  67. watchEffect(() => amMap[key].am?.changeTitle(data.title)),
  68. watchEffect(() => amMap[key].am?.visibilityTitle(data.showTitle)),
  69. watchEffect(() => amMap[key].am?.changeFontSize(data.fontSize))
  70. );
  71. const stopWatch = watch(
  72. () => ams.value.includes(data),
  73. (exists) => {
  74. if (!exists) {
  75. stopLoad();
  76. stopAttrib();
  77. stopWatch();
  78. }
  79. },
  80. { flush: "post" }
  81. );
  82. return new Promise((resolve) => {
  83. const stopWatch = watchEffect(() => {
  84. if (amMap[key]?.am) {
  85. resolve(amMap[key]!.am!);
  86. nextTick(() => stopWatch());
  87. }
  88. });
  89. });
  90. };
  91. export const addFrame = (
  92. data: AnimationModelFrame
  93. ): Promise<AnimationModelFrame3D> => {
  94. const am = ams.value.find((item) =>
  95. item.frames.find(({ id }) => id === data.id)
  96. );
  97. if (!am) {
  98. throw "找不到am数据";
  99. }
  100. const key = getAMKey(am);
  101. const stopLoad = watch(
  102. () => {
  103. const exists = am.frames.some(({ id }) => id === data.id);
  104. return [amMap[key], exists] as const;
  105. },
  106. ([map, exists]) => {
  107. if (!map.am) return;
  108. if (exists && !map.frames[data.id]) {
  109. map.frames[data.id] = map.am.addFrame(data);
  110. } else if (!exists && map.frames[data.id]) {
  111. map.frames[data.id].destory();
  112. delete map.frames[data.id];
  113. }
  114. }
  115. );
  116. const stopAttrib = mergeFuns(() =>
  117. watchEffect(() => amMap[key].frames[data.id]?.changeTime(data.time))
  118. );
  119. const stopWatch = watch(
  120. () => am.frames.includes(data),
  121. (exists) => {
  122. if (!exists) {
  123. stopLoad();
  124. stopAttrib();
  125. stopWatch();
  126. }
  127. },
  128. { flush: "post" }
  129. );
  130. return new Promise((resolve) => {
  131. const stopWatch = watchEffect(() => {
  132. if (amMap[key]?.frames[data.id]) {
  133. resolve(amMap[key].frames[data.id]);
  134. nextTick(() => stopWatch());
  135. }
  136. });
  137. });
  138. };
  139. export const addAction = (
  140. data: AnimationModelAction
  141. ): Promise<AnimationModelAction3D> => {
  142. const am = ams.value.find((item) =>
  143. item.actions.find(({ id }) => id === data.id)
  144. );
  145. if (!am) {
  146. throw "找不到am数据";
  147. }
  148. const key = getAMKey(am);
  149. const stopLoad = watch(
  150. () => {
  151. const exists = am.actions.some(({ id }) => id === data.id);
  152. return [amMap[key], exists] as const;
  153. },
  154. ([map, exists]) => {
  155. if (!map.am) return;
  156. if (exists && !map.actions[data.id]) {
  157. map.actions[data.id] = map.am.addAction(data);
  158. } else if (!exists && map.actions[data.id]) {
  159. map.actions[data.id].destory();
  160. delete map.actions[data.id];
  161. }
  162. }
  163. );
  164. const stopAttrib = mergeFuns(
  165. () => watchEffect(() => amMap[key].actions[data.id]?.changeTime(data.time)),
  166. () => watchEffect(() => amMap[key].actions[data.id]?.changeAmplitude(data.amplitude)),
  167. () => watchEffect(() => amMap[key].actions[data.id]?.changeSpeed(data.speed)),
  168. () => watchEffect(() => amMap[key].actions[data.id]?.changeDuration(data.duration)),
  169. );
  170. const stopWatch = watch(
  171. () => am.actions.includes(data),
  172. (exists) => {
  173. if (!exists) {
  174. stopLoad();
  175. stopAttrib();
  176. stopWatch();
  177. }
  178. },
  179. { flush: "post" }
  180. );
  181. return new Promise((resolve) => {
  182. const stopWatch = watchEffect(() => {
  183. if (amMap[key]?.actions[data.id]) {
  184. resolve(amMap[key].actions[data.id]);
  185. nextTick(() => stopWatch());
  186. }
  187. });
  188. });
  189. };
  190. export const addPath = (
  191. data: AnimationModelPath
  192. ): Promise<AnimationModelPath3D> => {
  193. const am = ams.value.find((item) =>
  194. item.paths.find(({ id }) => id === data.id)
  195. );
  196. if (!am) {
  197. throw "找不到am数据";
  198. }
  199. const path = computed(() => data.pathId ? getPathNode(data.pathId) : undefined)
  200. const key = getAMKey(am);
  201. const stopLoad = watch(
  202. () => {
  203. const exists = am.paths.some(({ id }) => id === data.id);
  204. return [amMap[key], exists, path.value] as const;
  205. },
  206. ([map, exists, path]) => {
  207. if (!map.am || !path) return;
  208. if (exists && !map.paths[data.id]) {
  209. map.paths[data.id] = map.am.addPath({...data, path});
  210. } else if (!exists && map.paths[data.id]) {
  211. map.paths[data.id].destory();
  212. delete map.paths[data.id];
  213. }
  214. }
  215. );
  216. const stopAttrib = mergeFuns(
  217. () => watchEffect(() => amMap[key].paths[data.id]?.changeTime(data.time)),
  218. () => watchEffect(() => amMap[key].paths[data.id]?.changeReverse(data.reverse)),
  219. () => watchEffect(() => amMap[key].paths[data.id]?.changeDuration(data.duration)),
  220. () => watchEffect(() => amMap[key].paths[data.id]?.changePath(path.value)),
  221. );
  222. const stopWatch = watch(
  223. () => am.paths.includes(data),
  224. (exists) => {
  225. if (!exists) {
  226. stopLoad();
  227. stopAttrib();
  228. stopWatch();
  229. }
  230. },
  231. { flush: "post" }
  232. );
  233. return new Promise((resolve) => {
  234. const stopWatch = watchEffect(() => {
  235. if (amMap[key]?.paths[data.id]) {
  236. resolve(amMap[key].paths[data.id]);
  237. nextTick(() => stopWatch());
  238. }
  239. });
  240. });
  241. };
  242. export const associationAnimation = (sdk: SDK, el: HTMLDivElement) => {
  243. animationGroup = sdk.createAnimationGroup();
  244. };