bill 5 months ago
parent
commit
f00538fb88
3 changed files with 155 additions and 39 deletions
  1. 1 0
      src/components/subtitle/index.vue
  2. 127 19
      src/sdk/association/animation.ts
  3. 27 20
      src/sdk/sdk.ts

+ 1 - 0
src/components/subtitle/index.vue

@@ -0,0 +1 @@
+<template></template>

+ 127 - 19
src/sdk/association/animation.ts

@@ -3,6 +3,7 @@ import {
   AnimationModelAction,
   AnimationModelFrame,
   AnimationModelPath,
+  AnimationModelSubtitle,
 } from "@/api";
 import {
   AnimationGroup,
@@ -13,10 +14,14 @@ import {
   SDK,
   sdk as _sdk,
 } from "../sdk";
-import { computed, nextTick, reactive, watch, watchEffect } from "vue";
+import { computed, nextTick, reactive, ref, watch, watchEffect } from "vue";
 import { ams } from "@/store/animation";
 import { mergeFuns } from "@/components/drawing/hook";
 import { getPathNode } from "./path";
+import { diffArrayChange, mount } from "@/utils";
+import { Pos } from "@/utils/event";
+import Subtitle from "@/components/subtitle/index.vue";
+import { Size } from "@/components/drawing/dec";
 
 export let animationGroup: AnimationGroup;
 const getAMKey = (am: AnimationModel) => am.key || am.id;
@@ -28,6 +33,7 @@ const amMap: Record<
     frames: Record<string, AnimationModelFrame3D>;
     actions: Record<string, AnimationModelAction3D>;
     paths: Record<string, AnimationModelPath3D>;
+    subtitles: Record<string, () => void>;
   }
 > = reactive({});
 export const addAM = (data: AnimationModel): Promise<AnimationModel3D> => {
@@ -51,6 +57,7 @@ export const addAM = (data: AnimationModel): Promise<AnimationModel3D> => {
           frames: {},
           actions: {},
           paths: {},
+          subtitles: {},
         };
         animationGroup
           .addAnimationModel(data)
@@ -61,12 +68,11 @@ export const addAM = (data: AnimationModel): Promise<AnimationModel3D> => {
   );
 
   const stopAttrib = mergeFuns(
-    () =>
-      watchEffect(() =>
-        amMap[key].am?.changeVisibilityRange(
-          data.globalVisibility ? undefined : data.visibilityRange
-        )
-      ),
+    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))
@@ -175,10 +181,14 @@ export const addAction = (
   );
 
   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)),
+    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(
@@ -203,7 +213,6 @@ export const addAction = (
   });
 };
 
-
 export const addPath = (
   data: AnimationModelPath
 ): Promise<AnimationModelPath3D> => {
@@ -213,7 +222,9 @@ export const addPath = (
   if (!am) {
     throw "找不到am数据";
   }
-  const path = computed(() => data.pathId ? getPathNode(data.pathId) : undefined)
+  const path = computed(() =>
+    data.pathId ? getPathNode(data.pathId) : undefined
+  );
   const key = getAMKey(am);
   const stopLoad = watch(
     () => {
@@ -223,7 +234,7 @@ export const addPath = (
     ([map, exists, path]) => {
       if (!map.am || !path) return;
       if (exists && !map.paths[data.id]) {
-        map.paths[data.id] = map.am.addPath({...data, path});
+        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];
@@ -232,10 +243,10 @@ export const addPath = (
   );
 
   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)),
+    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(
@@ -260,8 +271,105 @@ export const addPath = (
   });
 };
 
+export const addSubtitle = (data: AnimationModelSubtitle) => {
+  const am = ams.value.find((item) =>
+    item.subtitles.find(({ id }) => id === data.id)
+  );
+  if (!am) {
+    throw "找不到am数据";
+  }
+  const key = getAMKey(am);
+  const size = ref({ width: 0, height: 0 });
+  const show = ref(false)
+  const pixel = ref<Pos>();
+  const stopLoad = watch(
+    () => {
+      const exists = am.subtitles.some(({ id }) => id === data.id);
+      return [amMap[key], exists] as const;
+    },
+    ([map, exists]) => {
+      if (!map.am) return;
+      if (exists && !map.subtitles[data.id]) {
+        map.subtitles[data.id] = mount(
+          document.querySelector("#app")!,
+          Subtitle,
+          reactive({
+            pixel,
+            show,
+            data,
+            sizeChang: (csize: Size) => (size.value = csize),
+          })
+        );
+      } else if (!exists && map.subtitles[data.id]) {
+        map.subtitles[data.id]();
+        delete map.subtitles[data.id];
+      }
+    }
+  );
+
+  const stopAttrib = mergeFuns(
+    watch([currentTime, () => amMap[am.id].am, size], () => {
+      if (currentTime.value >= data.time && (data.time + data.duration) <= currentTime.value) {
+        amMap[am.id].am?.getCurrentSubtitlePixel(size.value)
+        show.value = true
+      } else {
+        show.value = false
+      }
+    })
+  );
+
+  const stopWatch = watch(
+    () => am.subtitles.includes(data),
+    (exists) => {
+      if (!exists) {
+        stopLoad();
+        stopAttrib();
+        stopWatch();
+      }
+    },
+    { flush: "post" }
+  );
+};
+
+export const currentTime = ref(0);
 export const associationAnimation = (sdk: SDK, el: HTMLDivElement) => {
   animationGroup = sdk.createAnimationGroup();
 
-  
+  watchEffect(() => {
+    animationGroup.setCurrentTime(currentTime.value);
+  });
+
+  animationGroup.bus.on('currentTime', time => currentTime.value = time)
+
+  watch(
+    () => [...ams.value],
+    (newv, oldv = []) => {
+      const { added } = diffArrayChange(newv, oldv);
+      added.forEach(addAM);
+    }
+  );
+
+  watch(
+    () => ams.value.flatMap((am) => am.frames),
+    (newv, oldv = []) => {
+      const { added } = diffArrayChange(newv, oldv);
+      added.forEach(addFrame);
+    }
+  );
+
+  watch(
+    () => ams.value.flatMap((am) => am.actions),
+    (newv, oldv = []) => {
+      const { added } = diffArrayChange(newv, oldv);
+      added.forEach(addAction);
+    }
+  );
+
+  watch(
+    () => ams.value.flatMap((am) => am.paths),
+    (newv, oldv = []) => {
+      const { added } = diffArrayChange(newv, oldv);
+      added.forEach(addPath);
+    }
+  );
 };

+ 27 - 20
src/sdk/sdk.ts

@@ -212,7 +212,7 @@ export interface SDK {
 
   createPath: (props: PathProps) => Path;
 
-  createAnimationGroup: () => AnimationGroup
+  createAnimationGroup: () => AnimationGroup;
 }
 
 export type PathProps = {
@@ -369,7 +369,11 @@ export type AnimationGroup = {
   addAnimationModel: (data: AnimationModel) => Promise<AnimationModel3D>;
 
   // 设置当前时间, 单位为秒
-  setCurrentTime: (s: number) => void
+  setCurrentTime: (s: number) => void;
+
+  bus: Emitter<{
+    currentTime: number;
+  }>;
 };
 
 export type AnimationModel3D = {
@@ -391,33 +395,38 @@ export type AnimationModel3D = {
   // 添加模型动作
   addAction: (frame: AnimationModelAction) => AnimationModelAction3D;
   // 添加模型路径
-  addPath: (frame: Omit<AnimationModelPath, 'pathId'> & {path: Path}) => AnimationModelPath3D;
+  addPath: (
+    frame: Omit<AnimationModelPath, "pathId"> & { path: Path }
+  ) => AnimationModelPath3D;
 
   // 获取当前模型旁白出现的适合位置,传入旁边dom的宽高,返回像素位置
-  getCurrentSubtitlePixel: (size: {width: number, height: number}) => {x: number, y: number}
+  getCurrentSubtitlePixel: (size: { width: number; height: number }) => {
+    x: number;
+    y: number;
+  };
   // 获取当前时间改模型的姿态
   getCurrentMat: () => {
     position?: SceneLocalPos;
     scale?: number;
     rotation?: SceneLocalPos;
-    originPosition?: SceneLocalPos
-  }
+    originPosition?: SceneLocalPos;
+  };
   // 设置当前操控模式, translate rotate scale originTranslate
-  setCurrentMode: (mode?: string) => void
+  setCurrentMode: (mode?: string) => void;
 };
 
 export type AnimationModelFrame3D = {
   // 销毁动画模型帧
   destory: () => void;
   // 修改帧播放时间 单位为秒
-  changeTime: (s: number) => void
+  changeTime: (s: number) => void;
   // 动画帧姿态修改数据
   bus: Emitter<{
     matChange: {
       position?: SceneLocalPos;
       scale?: number;
       rotation?: SceneLocalPos;
-      originPosition?: SceneLocalPos
+      originPosition?: SceneLocalPos;
     };
   }>;
 };
@@ -426,30 +435,28 @@ export type AnimationModelAction3D = {
   // 销毁动画模型动作
   destory: () => void;
   // 修改动作播放时间 单位为秒
-  changeTime: (s: number) => void
-  // 修改动作幅度  
-  changeAmplitude: (n: number) => void
+  changeTime: (s: number) => void;
+  // 修改动作幅度
+  changeAmplitude: (n: number) => void;
   // 修改动作速度
-  changeSpeed: (n: number) => void
+  changeSpeed: (n: number) => void;
   // 修改动持续时间 单位为秒
-  changeDuration: (n: number) => void
+  changeDuration: (n: number) => void;
 };
 
-
 export type AnimationModelPath3D = {
   // 销毁动画模型路径
   destory: () => void;
   // 修改路径 传入参数为你之前返回的路径对象
-  changePath: (path: Path | undefined) => void
+  changePath: (path: Path | undefined) => void;
   // 修改播放是否要反向
-  changeReverse: (reverse: boolean) => void
+  changeReverse: (reverse: boolean) => void;
   // 修改路径播放时间 单位为秒
-  changeTime: (s: number) => void
+  changeTime: (s: number) => void;
   // 修改路径续时间 单位为秒
-  changeDuration: (n: number) => void
+  changeDuration: (n: number) => void;
 };
 
-
 export let sdk: SDK;
 export type InialSDKProps = {
   laserRoot?: string;