Skip to content

Commit 16a6611

Browse files
committed
feat: add loader
1 parent ed10862 commit 16a6611

File tree

4 files changed

+379
-12
lines changed

4 files changed

+379
-12
lines changed

libs/angular-three/src/lib/loader.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import {
2+
isObservable,
3+
Observable,
4+
of,
5+
map,
6+
tap,
7+
from,
8+
retry,
9+
share,
10+
ReplaySubject,
11+
catchError,
12+
switchMap,
13+
forkJoin,
14+
take,
15+
} from 'rxjs';
16+
import type { GLTF } from 'three-stdlib';
17+
import type { NgtBranchingReturn, NgtLoaderExtensions, NgtLoaderResult, NgtObjectMap } from './types';
18+
import { makeObjectGraph } from './utils/make';
19+
20+
interface NgtLoader {
21+
<TReturnType, TUrl extends string | string[] | Record<string, string>>(
22+
loaderConstructorFactory: (inputs: TUrl) => new (...args: any[]) => NgtLoaderResult<TReturnType>,
23+
input: TUrl | Observable<TUrl>,
24+
extensions?: NgtLoaderExtensions,
25+
onProgress?: (event: ProgressEvent) => void
26+
): Observable<
27+
TUrl extends string[]
28+
? Array<NgtBranchingReturn<TReturnType, GLTF, GLTF & NgtObjectMap>>
29+
: TUrl extends object
30+
? { [key in keyof TUrl]: NgtBranchingReturn<TReturnType, GLTF, GLTF & NgtObjectMap> }
31+
: NgtBranchingReturn<TReturnType, GLTF, GLTF & NgtObjectMap>
32+
>;
33+
destroy: () => void;
34+
preLoad: <TReturnType, TUrl extends string | string[] | Record<string, string>>(
35+
loaderConstructorFactory: (inputs: TUrl) => new (...args: any[]) => NgtLoaderResult<TReturnType>,
36+
inputs: TUrl | Observable<TUrl>,
37+
extensions?: NgtLoaderExtensions
38+
) => void;
39+
}
40+
41+
export type NgtLoaderResults<
42+
TInput extends string | string[] | Record<string, string>,
43+
TReturn
44+
> = TInput extends string[] ? TReturn[] : TInput extends object ? { [key in keyof TInput]: TReturn } : TReturn;
45+
46+
const cached = new Map<string, Observable<any>>();
47+
48+
function injectLoader<TReturnType, TUrl extends string | string[] | Record<string, string>>(
49+
loaderConstructorFactory: (inputs: TUrl) => new (...args: any[]) => NgtLoaderResult<TReturnType>,
50+
input: TUrl | Observable<TUrl>,
51+
extensions?: NgtLoaderExtensions,
52+
onProgress?: (event: ProgressEvent) => void
53+
): Observable<NgtLoaderResults<TUrl, NgtBranchingReturn<TReturnType, GLTF, GLTF & NgtObjectMap>>> {
54+
const urls$ = isObservable(input) ? input : of(input);
55+
56+
return urls$.pipe(
57+
map((inputs) => {
58+
const loaderConstructor = loaderConstructorFactory(inputs);
59+
const loader = new loaderConstructor();
60+
if (extensions) {
61+
extensions(loader);
62+
}
63+
const urls = Array.isArray(inputs) ? inputs : typeof inputs === 'string' ? [inputs] : Object.values(inputs);
64+
return [
65+
urls.map((url) => {
66+
if (!cached.has(url)) {
67+
cached.set(
68+
url,
69+
from(loader.loadAsync(url, onProgress)).pipe(
70+
tap((data) => {
71+
if (data.scene) {
72+
Object.assign(data, makeObjectGraph(data.scene));
73+
}
74+
}),
75+
retry(2),
76+
catchError((err) => {
77+
console.error(`[NGT] Error loading ${url}: ${err.message}`);
78+
return of([]);
79+
}),
80+
share({
81+
connector: () => new ReplaySubject(1),
82+
resetOnComplete: true,
83+
resetOnError: true,
84+
resetOnRefCountZero: true,
85+
})
86+
)
87+
);
88+
}
89+
return cached.get(url);
90+
}),
91+
inputs,
92+
] as [Array<Observable<any>>, TUrl | TUrl[]];
93+
}),
94+
switchMap(([observables$, inputs]) => {
95+
return forkJoin(observables$).pipe(
96+
map((results) => {
97+
if (Array.isArray(inputs)) return results;
98+
if (typeof inputs === 'string') return results[0];
99+
const keys = Object.keys(inputs);
100+
return keys.reduce((result, key) => {
101+
result[key as keyof typeof result] = results[keys.indexOf(key)];
102+
return result;
103+
}, {} as { [key in keyof TUrl]: NgtBranchingReturn<TReturnType, GLTF, GLTF & NgtObjectMap> });
104+
})
105+
);
106+
})
107+
);
108+
}
109+
110+
(injectLoader as NgtLoader).destroy = () => {
111+
cached.clear();
112+
};
113+
114+
(injectLoader as NgtLoader).preLoad = (loaderConstructorFactory, inputs, extensions) => {
115+
injectLoader(loaderConstructorFactory, inputs, extensions).pipe(take(1)).subscribe();
116+
};

libs/angular-three/src/lib/stores/store.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ import * as THREE from 'three';
55
import { createLoop } from '../loop';
66
import type {
77
NgtBeforeRenderRecord,
8-
NgtCamera,
98
NgtCanvasInputs,
10-
NgtDomEvent,
119
NgtDpr,
1210
NgtEquConfig,
1311
NgtEventManager,

0 commit comments

Comments
 (0)