Skip to content

Commit

Permalink
fix|feat: seeking failed and timeline for new API
Browse files Browse the repository at this point in the history
  • Loading branch information
= committed Dec 20, 2024
1 parent 8cdde30 commit c7836ac
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 114 deletions.
26 changes: 18 additions & 8 deletions packages/core/src/animation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { WatchSource } from "vue";
import { getCurrentInstance, watch } from "vue";
import type { Ref, WatchSource } from "vue";
import { getCurrentInstance, ref, watch } from "vue";
import { usePlayer } from "./player";
import { Widget } from "./widget";

export type TimingFunction = (x: number) => number;
export const linear: TimingFunction = (x) => x;
Expand Down Expand Up @@ -136,7 +137,7 @@ export class AnimationManager<T> {

exec(fn: () => void) {
this.animate(
defineAnimation((_, __) => (progress) => {
defineAnimation(() => (progress) => {
if (progress === 0) fn();
}),
{ duration: 0 },
Expand All @@ -161,18 +162,27 @@ export function defineAnimation<T, A = object>(setup: AnimationSetup<T, A>) {
export function registerAnimation<T>(
name: string,
setup: (...args: any[]) => (animate: AnimationManager<T>) => void,
relativeElapsed?: WatchSource<number>,
widgetInstance?: Widget,
): void {
const current = getCurrentInstance();
const { widget } = current?.props as {
widget: T & { manager?: AnimationManager<T> };
};
if (widget) {
if (typeof widget.manager === "undefined") {
widget.manager = new AnimationManager<T>(
widget,
relativeElapsed ?? usePlayer().elapsed,
);
const elapsed: Ref<number> = ref(0);
if (widgetInstance && widgetInstance.elapsed) {
elapsed.value = widgetInstance.elapsed!;
watch(widgetInstance, (v) => {
elapsed.value = v.elapsed!;
});
} else {
watch(usePlayer().elapsed, (v) => {
elapsed.value = v;
console.log(v);
});
}
widget.manager = new AnimationManager<T>(widget, elapsed);
}
(widget as Record<string, any>)[name] = (
...args: Parameters<typeof setup>
Expand Down
28 changes: 20 additions & 8 deletions packages/core/src/player.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { App, Ref } from "vue";
import { inject, ref, watch } from "vue";
import { AnimationManager } from "./animation";
// import { GLOBAL_PLAYER } from "./symbols";

const studioListenerAdded = { value: false };

Expand All @@ -20,11 +21,11 @@ export function createPlayer(options: {
}

export function usePlayer() {
const startAt = performance.now() / 1000;
const elapsed = inject("elapsed") as Ref<number>;
const studio = inject("studio") as boolean;
const fps = inject("fps") as number;
const playing = ref(false);
const renderEvents: ((elapsed: number) => void)[] = [];

if (studio && !studioListenerAdded.value) {
studioListenerAdded.value = true;
Expand All @@ -35,26 +36,31 @@ export function usePlayer() {
});
}

function play() {
function play(to?: number) {
if (to) elapsed.value = to;
if (studio)
return console.log(
"You are in the studio mode, you are not supposed to call this function!",
);
renderEvents.forEach((fn) => fn(elapsed.value));
playing.value = true;
elapsed.value = performance.now() / 1000 - startAt;
if (playing.value) requestAnimationFrame(play);
// console.log(1 / fps)
elapsed.value += 1 / fps;
// console.log(elapsed.value)
if (playing.value) requestAnimationFrame(() => play());
}

function useAnimation<T extends object>(widget: T) {
return new AnimationManager(widget, elapsed);
}

function setElapsed(value: number) {
function seek(value: number) {
elapsed.value = value;
}

function pause() {
function pause(to?: number) {
playing.value = false;
if (to) elapsed.value = to;
}

function renderOnce(ela: number) {
Expand All @@ -63,17 +69,21 @@ export function usePlayer() {
}, 1000);
}

function whenRender(fn: (elapsed: number) => void) {
renderEvents.push(fn);
}

function useTimeline(start: number = 0) {
const relativeElapsed = ref<number>(0);
const isPlaying = ref(false);
const localStart = ref(start);

// 监听全局时间
watch(
elapsed,
() => {
if (isPlaying.value) {
relativeElapsed.value = Math.max(0, elapsed.value - localStart.value);
// console.log(relativeElapsed.value)
}
},
{ immediate: true },
Expand Down Expand Up @@ -116,10 +126,12 @@ export function usePlayer() {
elapsed,
useAnimation,
useTimeline,
setElapsed,
seek,
pause,
renderOnce,
whenRender,
};
}

export type Player = ReturnType<typeof usePlayer>;
export type Timeline = ReturnType<Player["useTimeline"]>;
1 change: 1 addition & 0 deletions packages/core/src/symbols.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const GLOBAL_PLAYER = Symbol("GLOBAL_PLAYER");
11 changes: 9 additions & 2 deletions packages/core/src/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import {
reactive,
ref,
useSlots,
watch,
} from "vue";
import type { AnimationManager } from "./animation";
import { Timeline } from "./player";

const childWidgets: InjectionKey<Ref<Widget[]>> = Symbol("child-widgets");

Expand All @@ -18,11 +20,16 @@ export interface Widget<T = any> {
slots?: Slots;
children?: Widget<T>[];
manager?: AnimationManager<T>;
wid?: string;
elapsed?: number;
}

export function useWidget<T extends Widget>(): Reactive<T> {
export function useWidget<T extends Widget>(timeline?: Timeline): Reactive<T> {
const widget = reactive({});
if (timeline) {
watch(timeline.elapsed, (v) => {
(widget as T).elapsed = v;
});
}
return widget as Reactive<T>;
}

Expand Down
Loading

0 comments on commit c7836ac

Please sign in to comment.