|
@@ -1,149 +1,168 @@
|
|
|
-import { onUnmounted, ref, Ref, watch } from "vue"
|
|
|
-import { Tween, Easing } from '@tweenjs/tween.js'
|
|
|
-import { inRevise, startAnimation } from "@/utils/shared.ts"
|
|
|
-import { Color, RGB } from "three"
|
|
|
-import { DC } from "@/deconstruction"
|
|
|
-import { Shape } from "konva/lib/Shape"
|
|
|
+import { onUnmounted, ref, Ref, watch } from "vue";
|
|
|
+import { Tween, Easing } from "@tweenjs/tween.js";
|
|
|
+import { inRevise, startAnimation } from "@/utils/shared.ts";
|
|
|
+import { Color, RGB } from "three";
|
|
|
+import { DC } from "@/deconstruction";
|
|
|
+import { Shape } from "konva/lib/Shape";
|
|
|
|
|
|
-export const animation = <T extends object>(origin: T, target: T, update?: (data: T) => void) => {
|
|
|
- let isStop = false
|
|
|
- const stop = () => {
|
|
|
- tw.stop()
|
|
|
- isStop = true
|
|
|
- }
|
|
|
+export const animation = <T extends object>(
|
|
|
+ origin: T,
|
|
|
+ target: T,
|
|
|
+ update?: (data: T) => void,
|
|
|
+ time = 300
|
|
|
+) => {
|
|
|
+ let stop: (() => void) & {promise: Promise<void>};
|
|
|
+ const promise = new Promise<void>((resolve, reject) => {
|
|
|
+ let isStop = false;
|
|
|
+ let isComp = false
|
|
|
+ stop = (() => {
|
|
|
+ tw.stop();
|
|
|
+ isStop = true;
|
|
|
+ isComp || reject('动画中断')
|
|
|
+ }) as any;
|
|
|
|
|
|
- const tw = new Tween(origin)
|
|
|
- .to(target, 300)
|
|
|
- .easing(easing)
|
|
|
- .start()
|
|
|
- .onComplete(() => {
|
|
|
- stop()
|
|
|
- })
|
|
|
- if (update) {
|
|
|
- tw.onUpdate(() => {
|
|
|
- update && update(origin)
|
|
|
- })
|
|
|
- }
|
|
|
+ const tw = new Tween(origin)
|
|
|
+ .to(target, time)
|
|
|
+ .easing(easing)
|
|
|
+ .start()
|
|
|
+ .onComplete(() => {
|
|
|
+ resolve()
|
|
|
+ isComp = true
|
|
|
+ stop();
|
|
|
+ });
|
|
|
+ if (update) {
|
|
|
+ tw.onUpdate(() => {
|
|
|
+ update && update(origin);
|
|
|
+ });
|
|
|
+ }
|
|
|
|
|
|
- const start = () => {
|
|
|
- requestAnimationFrame(() => {
|
|
|
- tw.update()
|
|
|
- isStop || start()
|
|
|
- })
|
|
|
- }
|
|
|
- start()
|
|
|
- return stop
|
|
|
-}
|
|
|
+ const start = () => {
|
|
|
+ requestAnimationFrame(() => {
|
|
|
+ tw.update();
|
|
|
+ isStop || start();
|
|
|
+ });
|
|
|
+ };
|
|
|
+ start();
|
|
|
+ });
|
|
|
+ stop!.promise = promise
|
|
|
+ return stop!;
|
|
|
+};
|
|
|
|
|
|
-const pickColors = <T extends object>(origin: T): Record<string, RGB> => {
|
|
|
- const originColors = {} as any
|
|
|
+const pickColors = <T extends object>(origin: T): Record<string, RGB> => {
|
|
|
+ const originColors = {} as any;
|
|
|
for (const [key, val] of Object.entries(origin)) {
|
|
|
- if (typeof val === 'string') {
|
|
|
- if (val.startsWith('#') || val.startsWith('rgb')) {
|
|
|
- originColors[key] = new Color(val).getRGB({} as any)
|
|
|
- }
|
|
|
+ if (typeof val === "string") {
|
|
|
+ if (val.startsWith("#") || val.startsWith("rgb")) {
|
|
|
+ originColors[key] = new Color(val).getRGB({} as any);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- return originColors
|
|
|
-}
|
|
|
-const resumeColors = <T extends object>(origin: T, colors: Record<string, RGB>) => {
|
|
|
+ return originColors;
|
|
|
+};
|
|
|
+const resumeColors = <T extends object>(
|
|
|
+ origin: T,
|
|
|
+ colors: Record<string, RGB>
|
|
|
+) => {
|
|
|
for (const [key, val] of Object.entries(colors)) {
|
|
|
- (origin as any)[key] = `#${new Color(val.r, val.g, val.b).getHexString()}`
|
|
|
+ (origin as any)[key] = `#${new Color(val.r, val.g, val.b).getHexString()}`;
|
|
|
}
|
|
|
-}
|
|
|
+};
|
|
|
|
|
|
-const easing = Easing.Quadratic.InOut
|
|
|
-const animationProperty = <T extends object>(origin: T, target: T, update?: (data: T) => void) => {
|
|
|
- let isStop = false
|
|
|
+const easing = Easing.Quadratic.InOut;
|
|
|
+const animationProperty = <T extends object>(
|
|
|
+ origin: T,
|
|
|
+ target: T,
|
|
|
+ update?: (data: T) => void
|
|
|
+) => {
|
|
|
+ let isStop = false;
|
|
|
const stop = () => {
|
|
|
- numTw.stop()
|
|
|
- colorTw.stop()
|
|
|
- isStop = true
|
|
|
- }
|
|
|
+ numTw.stop();
|
|
|
+ colorTw.stop();
|
|
|
+ isStop = true;
|
|
|
+ };
|
|
|
const oColors = pickColors(origin);
|
|
|
- const tColors = pickColors(target)
|
|
|
- const tOrigin = {...origin}
|
|
|
- const tTarget = {...target}
|
|
|
+ const tColors = pickColors(target);
|
|
|
+ const tOrigin = { ...origin };
|
|
|
+ const tTarget = { ...target };
|
|
|
|
|
|
for (const key in oColors) {
|
|
|
if (!(key in tColors)) {
|
|
|
- ;(origin as any)[key] = null
|
|
|
- delete oColors[key]
|
|
|
+ (origin as any)[key] = null;
|
|
|
+ delete oColors[key];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
for (const key in tOrigin) {
|
|
|
- if (typeof tOrigin[key] === 'string') {
|
|
|
- delete tOrigin[key]
|
|
|
+ if (typeof tOrigin[key] === "string") {
|
|
|
+ delete tOrigin[key];
|
|
|
}
|
|
|
}
|
|
|
for (const key in tTarget) {
|
|
|
- if (typeof tTarget[key] === 'string') {
|
|
|
- delete tTarget[key]
|
|
|
+ if (typeof tTarget[key] === "string") {
|
|
|
+ delete tTarget[key];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- let count = 0
|
|
|
+ let count = 0;
|
|
|
const tw = (origin: any, target: any) => {
|
|
|
- ++count
|
|
|
+ ++count;
|
|
|
return new Tween(origin)
|
|
|
.to(target, 300)
|
|
|
.easing(easing)
|
|
|
.start()
|
|
|
.onComplete(() => {
|
|
|
- if (--count === 0) stop()
|
|
|
- })
|
|
|
- }
|
|
|
+ if (--count === 0) stop();
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const numTw = tw(tOrigin, tTarget).onUpdate(() => {
|
|
|
+ Object.assign(origin, tOrigin);
|
|
|
+ update && update(origin);
|
|
|
+ });
|
|
|
|
|
|
- const numTw = tw(tOrigin, tTarget)
|
|
|
- .onUpdate(() => {
|
|
|
- Object.assign(origin, tOrigin)
|
|
|
- update && update(origin)
|
|
|
- })
|
|
|
-
|
|
|
- const colorTw = tw(oColors, tColors)
|
|
|
- .onUpdate(() => {
|
|
|
- resumeColors(origin, oColors)
|
|
|
- update && update(origin)
|
|
|
- })
|
|
|
+ const colorTw = tw(oColors, tColors).onUpdate(() => {
|
|
|
+ resumeColors(origin, oColors);
|
|
|
+ update && update(origin);
|
|
|
+ });
|
|
|
|
|
|
const start = () => {
|
|
|
requestAnimationFrame(() => {
|
|
|
- numTw.update()
|
|
|
- colorTw.update()
|
|
|
- isStop || start()
|
|
|
- })
|
|
|
- }
|
|
|
- start()
|
|
|
- return stop
|
|
|
-}
|
|
|
+ numTw.update();
|
|
|
+ colorTw.update();
|
|
|
+ isStop || start();
|
|
|
+ });
|
|
|
+ };
|
|
|
+ start();
|
|
|
+ return stop;
|
|
|
+};
|
|
|
|
|
|
export const useAniamtion = <T extends object>(data: Ref<T>) => {
|
|
|
- const atData = ref(JSON.parse(JSON.stringify(data.value))) as Ref<T>
|
|
|
- let animationStop: () => void
|
|
|
- let isPause = false
|
|
|
+ const atData = ref(JSON.parse(JSON.stringify(data.value))) as Ref<T>;
|
|
|
+ let animationStop: () => void;
|
|
|
+ let isPause = false;
|
|
|
watch(data, (newData) => {
|
|
|
if (!inRevise(newData, atData.value)) return;
|
|
|
- animationStop! && animationStop()
|
|
|
+ animationStop! && animationStop();
|
|
|
if (isPause) {
|
|
|
- atData.value = newData
|
|
|
+ atData.value = newData;
|
|
|
} else {
|
|
|
- animationStop = animationProperty(atData.value, newData)
|
|
|
+ animationStop = animationProperty(atData.value, newData);
|
|
|
}
|
|
|
- })
|
|
|
+ });
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
- animationStop && animationStop()
|
|
|
- })
|
|
|
- return [
|
|
|
- atData, () => isPause = true, () => isPause = false
|
|
|
- ] as const
|
|
|
-}
|
|
|
+ animationStop && animationStop();
|
|
|
+ });
|
|
|
+ return [atData, () => (isPause = true), () => (isPause = false)] as const;
|
|
|
+};
|
|
|
|
|
|
-type DA = DC<Shape> | undefined
|
|
|
+type DA = DC<Shape> | undefined;
|
|
|
export const useDashAnimation = (shapes: Ref<DA | DA[]>) => {
|
|
|
watch(
|
|
|
- () => (Array.isArray(shapes.value) ? shapes.value : [shapes.value]).map((i) => i),
|
|
|
+ () =>
|
|
|
+ (Array.isArray(shapes.value) ? shapes.value : [shapes.value]).map(
|
|
|
+ (i) => i
|
|
|
+ ),
|
|
|
(shapes, _, onCleanup) => {
|
|
|
for (const shape of shapes) {
|
|
|
if (!shape) continue;
|
|
@@ -157,4 +176,4 @@ export const useDashAnimation = (shapes: Ref<DA | DA[]>) => {
|
|
|
}
|
|
|
}
|
|
|
);
|
|
|
-}
|
|
|
+};
|