This commit is contained in:
63
src/event/bridge.ts
Normal file
63
src/event/bridge.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { emit, on, once, off, Emitter } from './bus';
|
||||
import {
|
||||
ModelClickPayload,
|
||||
ModelLoadedPayload,
|
||||
ModelLoadErrorPayload,
|
||||
ModelLoadProgressPayload,
|
||||
SceneReadyPayload
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* Centralized event helpers to avoid spreading raw event strings.
|
||||
*/
|
||||
export class EventBridge {
|
||||
// Emits
|
||||
static modelLoadProgress(payload: ModelLoadProgressPayload): Emitter {
|
||||
return emit("model:load:progress", payload);
|
||||
}
|
||||
|
||||
static modelLoadError(payload: ModelLoadErrorPayload): Emitter {
|
||||
return emit("model:load:error", payload);
|
||||
}
|
||||
|
||||
static modelLoaded(payload: ModelLoadedPayload): Emitter {
|
||||
return emit("model:loaded", payload);
|
||||
}
|
||||
|
||||
static modelClick(payload: ModelClickPayload): Emitter {
|
||||
return emit("model:click", payload);
|
||||
}
|
||||
|
||||
static sceneReady(payload: SceneReadyPayload): Emitter {
|
||||
return emit("scene:ready", payload);
|
||||
}
|
||||
|
||||
// Listeners
|
||||
static onModelLoadProgress(callback: (payload: ModelLoadProgressPayload) => void, context?: unknown): Emitter {
|
||||
return on("model:load:progress", callback, context);
|
||||
}
|
||||
|
||||
static onModelLoadError(callback: (payload: ModelLoadErrorPayload) => void, context?: unknown): Emitter {
|
||||
return on("model:load:error", callback, context);
|
||||
}
|
||||
|
||||
static onModelLoaded(callback: (payload: ModelLoadedPayload) => void, context?: unknown): Emitter {
|
||||
return on("model:loaded", callback, context);
|
||||
}
|
||||
|
||||
static onModelClick(callback: (payload: ModelClickPayload) => void, context?: unknown): Emitter {
|
||||
return on("model:click", callback, context);
|
||||
}
|
||||
|
||||
static onSceneReady(callback: (payload: SceneReadyPayload) => void, context?: unknown): Emitter {
|
||||
return on("scene:ready", callback, context);
|
||||
}
|
||||
|
||||
static onceSceneReady(callback: (payload: SceneReadyPayload) => void, context?: unknown): Emitter {
|
||||
return once("scene:ready", callback, context);
|
||||
}
|
||||
|
||||
static off(eventName?: string, callback?: (...args: unknown[]) => void): Emitter {
|
||||
return off(eventName, callback);
|
||||
}
|
||||
}
|
||||
82
src/event/bus.ts
Normal file
82
src/event/bus.ts
Normal file
@ -0,0 +1,82 @@
|
||||
type Listener = {
|
||||
callback: (...args: unknown[]) => void;
|
||||
context?: unknown;
|
||||
};
|
||||
|
||||
export class Emitter {
|
||||
private _events: Record<string, Listener[]> = {};
|
||||
|
||||
on(name: string, callback: (...args: unknown[]) => void, context?: unknown): this {
|
||||
if (!this._events[name]) {
|
||||
this._events[name] = [];
|
||||
}
|
||||
this._events[name].push({ callback, context });
|
||||
return this;
|
||||
}
|
||||
|
||||
once(name: string, callback: (...args: unknown[]) => void, context?: unknown): this {
|
||||
const onceWrapper = (...args: unknown[]) => {
|
||||
this.off(name, onceWrapper);
|
||||
callback.apply(context, args);
|
||||
};
|
||||
return this.on(name, onceWrapper, context);
|
||||
}
|
||||
|
||||
off(name?: string, callback?: (...args: unknown[]) => void): this {
|
||||
if (!name) {
|
||||
this._events = {};
|
||||
return this;
|
||||
}
|
||||
if (!this._events[name]) return this;
|
||||
if (!callback) {
|
||||
delete this._events[name];
|
||||
return this;
|
||||
}
|
||||
this._events[name] = this._events[name].filter(
|
||||
listener => listener.callback !== callback
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
removeAllListeners(): this {
|
||||
this._events = {};
|
||||
return this;
|
||||
}
|
||||
|
||||
emit(name: string, ...args: unknown[]): this {
|
||||
if (!this._events[name]) return this;
|
||||
this._events[name].forEach(listener => {
|
||||
listener.callback.apply(listener.context, args);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
listenerCount(name: string): number {
|
||||
return this._events[name]?.length ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class EventBus extends Emitter { }
|
||||
|
||||
export const eventBus = new EventBus();
|
||||
|
||||
export const on = (eventName: string, callback: (...args: unknown[]) => void, context?: unknown): Emitter => {
|
||||
return eventBus.on(eventName, callback, context);
|
||||
};
|
||||
|
||||
export const off = (eventName?: string, callback?: (...args: unknown[]) => void): Emitter => {
|
||||
return eventBus.off(eventName, callback);
|
||||
};
|
||||
|
||||
export const once = (eventName: string, callback: (...args: unknown[]) => void, context?: unknown): Emitter => {
|
||||
return eventBus.once(eventName, callback, context);
|
||||
};
|
||||
|
||||
export const emit = (eventName: string, ...args: unknown[]): Emitter => {
|
||||
return eventBus.emit(eventName, ...args);
|
||||
};
|
||||
|
||||
export const removeAllListeners = (eventName?: string): Emitter => {
|
||||
if (eventName) return eventBus.off(eventName);
|
||||
return eventBus.removeAllListeners();
|
||||
};
|
||||
37
src/event/types.ts
Normal file
37
src/event/types.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { Scene } from '@babylonjs/core/scene';
|
||||
|
||||
|
||||
export type ModelLoadProgressDetail = {
|
||||
url?: string;
|
||||
lengthComputable?: boolean;
|
||||
loadedBytes?: number;
|
||||
totalBytes?: number;
|
||||
};
|
||||
|
||||
export type ModelLoadProgressPayload = {
|
||||
loaded: number;
|
||||
total: number;
|
||||
url?: string;
|
||||
urls?: string[];
|
||||
success?: boolean;
|
||||
progress?: number;
|
||||
percentage?: number;
|
||||
detail?: ModelLoadProgressDetail;
|
||||
};
|
||||
|
||||
export type ModelLoadErrorPayload = {
|
||||
url: string;
|
||||
error?: unknown;
|
||||
};
|
||||
|
||||
export type ModelLoadedPayload = {
|
||||
urls: string[];
|
||||
};
|
||||
|
||||
export type ModelClickPayload = {
|
||||
meshName?: string;
|
||||
};
|
||||
|
||||
export type SceneReadyPayload = {
|
||||
scene: Scene | null;
|
||||
};
|
||||
Reference in New Issue
Block a user