angular-three 1.10.2 → 2.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -5
- package/esm2022/index.mjs +5 -7
- package/esm2022/lib/canvas.mjs +138 -99
- package/esm2022/lib/di/before-render.mjs +7 -10
- package/esm2022/lib/di/ref.mjs +38 -59
- package/esm2022/lib/directives/args.mjs +5 -8
- package/esm2022/lib/directives/common.mjs +20 -13
- package/esm2022/lib/directives/parent.mjs +5 -8
- package/esm2022/lib/{web → dom}/events.mjs +1 -1
- package/esm2022/lib/events.mjs +2 -2
- package/esm2022/lib/loader.mjs +58 -44
- package/esm2022/lib/loop.mjs +6 -8
- package/esm2022/lib/portal.mjs +76 -63
- package/esm2022/lib/renderer/provider.mjs +3 -2
- package/esm2022/lib/renderer/renderer.mjs +53 -52
- package/esm2022/lib/renderer/store.mjs +14 -19
- package/esm2022/lib/renderer/utils.mjs +27 -18
- package/esm2022/lib/routed-scene.mjs +12 -10
- package/esm2022/lib/stores/signal.store.mjs +60 -0
- package/esm2022/lib/stores/store.mjs +69 -48
- package/esm2022/lib/three-types.mjs +2 -0
- package/esm2022/lib/types.mjs +1 -1
- package/esm2022/lib/utils/apply-props.mjs +11 -7
- package/esm2022/lib/utils/attach.mjs +1 -1
- package/esm2022/lib/utils/instance.mjs +14 -14
- package/esm2022/lib/utils/safe-detect-changes.mjs +1 -1
- package/fesm2022/angular-three.mjs +1673 -1744
- package/fesm2022/angular-three.mjs.map +1 -1
- package/index.d.ts +4 -6
- package/lib/canvas.d.ts +11 -20
- package/lib/di/before-render.d.ts +5 -1
- package/lib/di/ref.d.ts +5 -11
- package/lib/directives/args.d.ts +6 -6
- package/lib/directives/common.d.ts +1 -4
- package/lib/directives/parent.d.ts +1 -1
- package/lib/{web → dom}/events.d.ts +2 -2
- package/lib/events.d.ts +3 -3
- package/lib/loader.d.ts +6 -2
- package/lib/loop.d.ts +4 -4
- package/lib/portal.d.ts +11 -18
- package/lib/renderer/renderer.d.ts +7 -9
- package/lib/renderer/store.d.ts +3 -5
- package/lib/renderer/utils.d.ts +6 -4
- package/lib/routed-scene.d.ts +4 -2
- package/lib/stores/signal.store.d.ts +19 -0
- package/lib/stores/store.d.ts +4 -7
- package/lib/three-types.d.ts +306 -0
- package/lib/types.d.ts +22 -25
- package/lib/utils/attach.d.ts +2 -2
- package/lib/utils/instance.d.ts +1 -1
- package/package.json +6 -7
- package/plugin/package.json +1 -1
- package/plugin/src/generators/init/init.d.ts +1 -1
- package/plugin/src/generators/init/init.js +1 -1
- package/esm2022/lib/di/destroy.mjs +0 -23
- package/esm2022/lib/di/run-in-context.mjs +0 -40
- package/esm2022/lib/pipes/push.mjs +0 -50
- package/esm2022/lib/stores/rx-store.mjs +0 -108
- package/lib/di/destroy.d.ts +0 -9
- package/lib/di/run-in-context.d.ts +0 -6
- package/lib/pipes/push.d.ts +0 -16
- package/lib/stores/rx-store.d.ts +0 -42
|
@@ -1,264 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ChangeDetectorRef,
|
|
2
|
+
import { ElementRef, signal, untracked, computed, assertInInjectionContext, runInInjectionContext, inject, ChangeDetectorRef, effect, Injector, Injectable, Optional, Inject, InjectionToken, EventEmitter, ViewContainerRef, NgZone, TemplateRef, Directive, Input, getDebugNode, RendererFactory2, makeEnvironmentProviders, provideZoneChangeDetection, EnvironmentInjector, DestroyRef, createEnvironmentInjector, Component, ChangeDetectionStrategy, Output, ViewChild, SkipSelf, ContentChild } from '@angular/core';
|
|
3
3
|
import { provideNgxResizeOptions, NgxResize } from 'ngx-resize';
|
|
4
|
-
import { isObservable, of, map, from, tap, retry, catchError, share, ReplaySubject, switchMap, forkJoin, take, BehaviorSubject, startWith, combineLatest, filter, distinctUntilChanged, takeUntil, merge } from 'rxjs';
|
|
5
4
|
import * as THREE from 'three';
|
|
6
5
|
import { DOCUMENT, NgForOf, NgIf } from '@angular/common';
|
|
7
|
-
import {
|
|
6
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
8
7
|
import * as i1 from '@angular/router';
|
|
9
8
|
import { ActivationEnd, RouterOutlet } from '@angular/router';
|
|
10
|
-
|
|
11
|
-
const idCache = {};
|
|
12
|
-
function makeId(event) {
|
|
13
|
-
if (event) {
|
|
14
|
-
return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
|
|
15
|
-
}
|
|
16
|
-
const newId = THREE.MathUtils.generateUUID();
|
|
17
|
-
// ensure not already used
|
|
18
|
-
if (!idCache[newId]) {
|
|
19
|
-
idCache[newId] = true;
|
|
20
|
-
return newId;
|
|
21
|
-
}
|
|
22
|
-
return makeId();
|
|
23
|
-
}
|
|
24
|
-
function makeDpr(dpr, window) {
|
|
25
|
-
const target = window?.devicePixelRatio || 1;
|
|
26
|
-
return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], target), dpr[1]) : dpr;
|
|
27
|
-
}
|
|
28
|
-
function makeDefaultCamera(isOrthographic, size) {
|
|
29
|
-
if (isOrthographic)
|
|
30
|
-
return new THREE.OrthographicCamera(0, 0, 0, 0, 0.1, 1000);
|
|
31
|
-
return new THREE.PerspectiveCamera(75, size.width / size.height, 0.1, 1000);
|
|
32
|
-
}
|
|
33
|
-
function makeDefaultRenderer(glOptions, canvasElement) {
|
|
34
|
-
const customRenderer = (typeof glOptions === 'function' ? glOptions(canvasElement) : glOptions);
|
|
35
|
-
if (customRenderer?.render != null)
|
|
36
|
-
return customRenderer;
|
|
37
|
-
return new THREE.WebGLRenderer({
|
|
38
|
-
powerPreference: 'high-performance',
|
|
39
|
-
canvas: canvasElement,
|
|
40
|
-
antialias: true,
|
|
41
|
-
alpha: true,
|
|
42
|
-
...(glOptions || {}),
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
function makeObjectGraph(object) {
|
|
46
|
-
const data = { nodes: {}, materials: {} };
|
|
47
|
-
if (object) {
|
|
48
|
-
object.traverse((child) => {
|
|
49
|
-
if (child.name)
|
|
50
|
-
data.nodes[child.name] = child;
|
|
51
|
-
if ('material' in child && !data.materials[child.material.name]) {
|
|
52
|
-
data.materials[child.material.name] = child
|
|
53
|
-
.material;
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
return data;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function safeDetectChanges(cdr) {
|
|
61
|
-
if (!cdr)
|
|
62
|
-
return;
|
|
63
|
-
try {
|
|
64
|
-
// dynamic created component with ViewContainerRef#createComponent does not have Context
|
|
65
|
-
// but it has _attachedToViewContainer
|
|
66
|
-
if (cdr['context'] || cdr['_attachedToViewContainer']) {
|
|
67
|
-
cdr.detectChanges();
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
catch (e) {
|
|
71
|
-
cdr.markForCheck();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const cached = new Map();
|
|
76
|
-
function load(loaderConstructorFactory, input, extensions, onProgress) {
|
|
77
|
-
const urls$ = isObservable(input) ? input : of(input);
|
|
78
|
-
return urls$.pipe(map((inputs) => {
|
|
79
|
-
const loaderConstructor = loaderConstructorFactory(inputs);
|
|
80
|
-
const loader = new loaderConstructor();
|
|
81
|
-
if (extensions)
|
|
82
|
-
extensions(loader);
|
|
83
|
-
const urls = Array.isArray(inputs) ? inputs : typeof inputs === 'string' ? [inputs] : Object.values(inputs);
|
|
84
|
-
return [
|
|
85
|
-
urls.map((url) => {
|
|
86
|
-
if (!cached.has(url)) {
|
|
87
|
-
cached.set(url, from(loader.loadAsync(url, onProgress)).pipe(tap((data) => {
|
|
88
|
-
if (data['scene'])
|
|
89
|
-
Object.assign(data, makeObjectGraph(data['scene']));
|
|
90
|
-
}), retry(2), catchError((err) => {
|
|
91
|
-
console.error(`[NGT] Error loading ${url}: ${err.message}`);
|
|
92
|
-
return of([]);
|
|
93
|
-
}), share({ connector: () => new ReplaySubject(1) })));
|
|
94
|
-
}
|
|
95
|
-
return cached.get(url);
|
|
96
|
-
}),
|
|
97
|
-
inputs,
|
|
98
|
-
];
|
|
99
|
-
}));
|
|
100
|
-
}
|
|
101
|
-
function injectNgtLoader(loaderConstructorFactory, input, extensions, onProgress) {
|
|
102
|
-
const cdr = inject(ChangeDetectorRef);
|
|
103
|
-
return load(loaderConstructorFactory, input, extensions, onProgress).pipe(switchMap(([observables$, inputs]) => {
|
|
104
|
-
return forkJoin(observables$).pipe(map((results) => {
|
|
105
|
-
if (Array.isArray(inputs))
|
|
106
|
-
return results;
|
|
107
|
-
if (typeof inputs === 'string')
|
|
108
|
-
return results[0];
|
|
109
|
-
const keys = Object.keys(inputs);
|
|
110
|
-
return keys.reduce((result, key) => {
|
|
111
|
-
result[key] = results[keys.indexOf(key)];
|
|
112
|
-
return result;
|
|
113
|
-
}, {});
|
|
114
|
-
}), tap(() => {
|
|
115
|
-
requestAnimationFrame(() => void safeDetectChanges(cdr));
|
|
116
|
-
}));
|
|
117
|
-
}));
|
|
118
|
-
}
|
|
119
|
-
injectNgtLoader['destroy'] = () => {
|
|
120
|
-
cached.clear();
|
|
121
|
-
};
|
|
122
|
-
injectNgtLoader['preLoad'] = (loaderConstructorFactory, inputs, extensions) => {
|
|
123
|
-
load(loaderConstructorFactory, inputs, extensions).pipe(take(1)).subscribe();
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
function createSubs(callback, subs) {
|
|
127
|
-
const sub = { callback };
|
|
128
|
-
subs.add(sub);
|
|
129
|
-
return () => void subs.delete(sub);
|
|
130
|
-
}
|
|
131
|
-
const globalEffects = new Set();
|
|
132
|
-
const globalAfterEffects = new Set();
|
|
133
|
-
const globalTailEffects = new Set();
|
|
134
|
-
/**
|
|
135
|
-
* Adds a global render callback which is called each frame.
|
|
136
|
-
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addEffect
|
|
137
|
-
*/
|
|
138
|
-
const addEffect = (callback) => createSubs(callback, globalEffects);
|
|
139
|
-
/**
|
|
140
|
-
* Adds a global after-render callback which is called each frame.
|
|
141
|
-
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addAfterEffect
|
|
142
|
-
*/
|
|
143
|
-
const addAfterEffect = (callback) => createSubs(callback, globalAfterEffects);
|
|
144
|
-
/**
|
|
145
|
-
* Adds a global callback which is called when rendering stops.
|
|
146
|
-
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addTail
|
|
147
|
-
*/
|
|
148
|
-
const addTail = (callback) => createSubs(callback, globalTailEffects);
|
|
149
|
-
function run(effects, timestamp) {
|
|
150
|
-
if (!effects.size)
|
|
151
|
-
return;
|
|
152
|
-
for (const { callback } of effects.values()) {
|
|
153
|
-
callback(timestamp);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
function flushGlobalEffects(type, timestamp) {
|
|
157
|
-
switch (type) {
|
|
158
|
-
case 'before':
|
|
159
|
-
return run(globalEffects, timestamp);
|
|
160
|
-
case 'after':
|
|
161
|
-
return run(globalAfterEffects, timestamp);
|
|
162
|
-
case 'tail':
|
|
163
|
-
return run(globalTailEffects, timestamp);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
function render(timestamp, store, frame) {
|
|
167
|
-
const state = store.get();
|
|
168
|
-
// Run local effects
|
|
169
|
-
let delta = state.clock.getDelta();
|
|
170
|
-
// In frameloop='never' mode, clock times are updated using the provided timestamp
|
|
171
|
-
if (state.frameloop === 'never' && typeof timestamp === 'number') {
|
|
172
|
-
delta = timestamp - state.clock.elapsedTime;
|
|
173
|
-
state.clock.oldTime = state.clock.elapsedTime;
|
|
174
|
-
state.clock.elapsedTime = timestamp;
|
|
175
|
-
}
|
|
176
|
-
// Call subscribers (useFrame)
|
|
177
|
-
// subscribers = state.internal.subscribers;
|
|
178
|
-
for (let i = 0; i < state.internal.subscribers.length; i++) {
|
|
179
|
-
const subscriber = state.internal.subscribers[i];
|
|
180
|
-
subscriber.callback({ ...state, delta, frame });
|
|
181
|
-
}
|
|
182
|
-
// Render content
|
|
183
|
-
if (!state.internal.priority && state.gl.render) {
|
|
184
|
-
state.gl.render(state.scene, state.camera);
|
|
185
|
-
}
|
|
186
|
-
// Decrease frame count
|
|
187
|
-
state.internal.frames = Math.max(0, state.internal.frames - 1);
|
|
188
|
-
return state.frameloop === 'always' ? 1 : state.internal.frames;
|
|
189
|
-
}
|
|
190
|
-
function createLoop(roots) {
|
|
191
|
-
let running = false;
|
|
192
|
-
let repeat;
|
|
193
|
-
let frame;
|
|
194
|
-
function loop(timestamp) {
|
|
195
|
-
frame = requestAnimationFrame(loop);
|
|
196
|
-
running = true;
|
|
197
|
-
repeat = 0;
|
|
198
|
-
// Run effects
|
|
199
|
-
flushGlobalEffects('before', timestamp);
|
|
200
|
-
// Render all roots
|
|
201
|
-
for (const root of roots.values()) {
|
|
202
|
-
const state = root.get();
|
|
203
|
-
// If the frameloop is invalidated, do not run another frame
|
|
204
|
-
if (state.internal.active &&
|
|
205
|
-
(state.frameloop === 'always' || state.internal.frames > 0) &&
|
|
206
|
-
!state.gl.xr?.isPresenting) {
|
|
207
|
-
repeat += render(timestamp, root);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// Run after-effects
|
|
211
|
-
flushGlobalEffects('after', timestamp);
|
|
212
|
-
// Stop the loop if nothing invalidates it
|
|
213
|
-
if (repeat === 0) {
|
|
214
|
-
// Tail call effects, they are called when rendering stops
|
|
215
|
-
flushGlobalEffects('tail', timestamp);
|
|
216
|
-
// Flag end of operation
|
|
217
|
-
running = false;
|
|
218
|
-
return cancelAnimationFrame(frame);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
function invalidate(store, frames = 1) {
|
|
222
|
-
const state = store?.get();
|
|
223
|
-
if (!state)
|
|
224
|
-
return roots.forEach((root) => invalidate(root, frames));
|
|
225
|
-
if (state.gl.xr?.isPresenting || !state.internal.active || state.frameloop === 'never')
|
|
226
|
-
return;
|
|
227
|
-
// Increase frames, do not go higher than 60
|
|
228
|
-
state.internal.frames = Math.min(60, state.internal.frames + frames);
|
|
229
|
-
// If the render-loop isn't active, start it
|
|
230
|
-
if (!running) {
|
|
231
|
-
running = true;
|
|
232
|
-
requestAnimationFrame(loop);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
function advance(timestamp, runGlobalEffects = true, store, frame) {
|
|
236
|
-
const state = store?.get();
|
|
237
|
-
if (runGlobalEffects)
|
|
238
|
-
flushGlobalEffects('before', timestamp);
|
|
239
|
-
if (!state)
|
|
240
|
-
for (const root of roots.values())
|
|
241
|
-
render(timestamp, root);
|
|
242
|
-
// safe to assume store is available here
|
|
243
|
-
else
|
|
244
|
-
render(timestamp, store, frame);
|
|
245
|
-
if (runGlobalEffects)
|
|
246
|
-
flushGlobalEffects('after', timestamp);
|
|
247
|
-
}
|
|
248
|
-
return {
|
|
249
|
-
loop,
|
|
250
|
-
/**
|
|
251
|
-
* Invalidates the view, requesting a frame to be rendered. Will globally invalidate unless passed a root's state.
|
|
252
|
-
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#invalidate
|
|
253
|
-
*/
|
|
254
|
-
invalidate,
|
|
255
|
-
/**
|
|
256
|
-
* Advances the frameloop and runs render effects, useful for when manually rendering via `frameloop="never"`.
|
|
257
|
-
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#advance
|
|
258
|
-
*/
|
|
259
|
-
advance,
|
|
260
|
-
};
|
|
261
|
-
}
|
|
9
|
+
import { filter } from 'rxjs';
|
|
262
10
|
|
|
263
11
|
const is = {
|
|
264
12
|
obj: (a) => a === Object(a) && !Array.isArray(a) && typeof a !== 'function',
|
|
@@ -353,35 +101,35 @@ function invalidateInstance(instance) {
|
|
|
353
101
|
checkUpdate(instance);
|
|
354
102
|
}
|
|
355
103
|
function prepare(object, localState) {
|
|
356
|
-
const instance =
|
|
104
|
+
const instance = object;
|
|
357
105
|
if (localState?.primitive || !instance.__ngt__) {
|
|
358
|
-
const { objects =
|
|
106
|
+
const { objects = signal([]), nonObjects = signal([]), ...rest } = localState || {};
|
|
359
107
|
instance.__ngt__ = {
|
|
360
108
|
previousAttach: null,
|
|
361
109
|
store: null,
|
|
362
|
-
parent: null,
|
|
110
|
+
parent: signal(null),
|
|
363
111
|
memoized: {},
|
|
364
112
|
eventCount: 0,
|
|
365
113
|
handlers: {},
|
|
366
114
|
objects,
|
|
367
115
|
nonObjects,
|
|
368
116
|
add: (object, type) => {
|
|
369
|
-
const current = instance.__ngt__[type]
|
|
117
|
+
const current = untracked(instance.__ngt__[type]);
|
|
370
118
|
const foundIndex = current.indexOf((obj) => obj === object);
|
|
371
119
|
if (foundIndex > -1) {
|
|
372
120
|
// if we add an object with the same reference, then we switch it out
|
|
373
121
|
// and update the BehaviorSubject
|
|
374
122
|
current.splice(foundIndex, 1, object);
|
|
375
|
-
instance.__ngt__[type].
|
|
123
|
+
instance.__ngt__[type].set(current);
|
|
376
124
|
}
|
|
377
125
|
else {
|
|
378
|
-
instance.__ngt__[type].
|
|
126
|
+
instance.__ngt__[type].update((prev) => [...prev, object]);
|
|
379
127
|
}
|
|
380
|
-
notifyAncestors(instance.__ngt__.parent);
|
|
128
|
+
notifyAncestors(untracked(instance.__ngt__.parent));
|
|
381
129
|
},
|
|
382
130
|
remove: (object, type) => {
|
|
383
|
-
instance.__ngt__[type].
|
|
384
|
-
notifyAncestors(instance.__ngt__.parent);
|
|
131
|
+
instance.__ngt__[type].update((prev) => prev.filter((o) => o !== object));
|
|
132
|
+
notifyAncestors(untracked(instance.__ngt__.parent));
|
|
385
133
|
},
|
|
386
134
|
...rest,
|
|
387
135
|
};
|
|
@@ -393,1045 +141,1266 @@ function notifyAncestors(instance) {
|
|
|
393
141
|
return;
|
|
394
142
|
const localState = getLocalState(instance);
|
|
395
143
|
if (localState.objects)
|
|
396
|
-
localState.objects.
|
|
144
|
+
localState.objects.update((prev) => prev);
|
|
397
145
|
if (localState.nonObjects)
|
|
398
|
-
localState.nonObjects.
|
|
399
|
-
notifyAncestors(localState.parent);
|
|
146
|
+
localState.nonObjects.update((prev) => prev);
|
|
147
|
+
notifyAncestors(untracked(localState.parent));
|
|
400
148
|
}
|
|
401
149
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
if (is.equ(propValue, instance[propKey]))
|
|
407
|
-
continue;
|
|
408
|
-
changes.push([propKey, propValue]);
|
|
150
|
+
const idCache = {};
|
|
151
|
+
function makeId(event) {
|
|
152
|
+
if (event) {
|
|
153
|
+
return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
|
|
409
154
|
}
|
|
410
|
-
|
|
155
|
+
const newId = THREE.MathUtils.generateUUID();
|
|
156
|
+
// ensure not already used
|
|
157
|
+
if (!idCache[newId]) {
|
|
158
|
+
idCache[newId] = true;
|
|
159
|
+
return newId;
|
|
160
|
+
}
|
|
161
|
+
return makeId();
|
|
411
162
|
}
|
|
412
|
-
function
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
return instance;
|
|
416
|
-
// filter equals, events , and reserved props
|
|
417
|
-
const localState = getLocalState(instance);
|
|
418
|
-
const rootState = localState.store?.get();
|
|
419
|
-
const changes = diffProps(instance, props);
|
|
420
|
-
for (let i = 0; i < changes.length; i++) {
|
|
421
|
-
let key = changes[i][0];
|
|
422
|
-
const currentInstance = instance;
|
|
423
|
-
const targetProp = currentInstance[key];
|
|
424
|
-
let value = changes[i][1];
|
|
425
|
-
if (is.colorSpaceExist(currentInstance)) {
|
|
426
|
-
const sRGBEncoding = 3001;
|
|
427
|
-
const SRGBColorSpace = 'srgb';
|
|
428
|
-
const LinearSRGBColorSpace = 'srgb-linear';
|
|
429
|
-
if (key === 'encoding') {
|
|
430
|
-
key = 'colorSpace';
|
|
431
|
-
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
432
|
-
}
|
|
433
|
-
else if (key === 'outputEncoding') {
|
|
434
|
-
key = 'outputColorSpace';
|
|
435
|
-
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
// special treatmen for objects with support for set/copy, and layers
|
|
439
|
-
if (targetProp && targetProp['set'] && (targetProp['copy'] || targetProp instanceof THREE.Layers)) {
|
|
440
|
-
const isColor = targetProp instanceof THREE.Color;
|
|
441
|
-
// if value is an array
|
|
442
|
-
if (Array.isArray(value)) {
|
|
443
|
-
if (targetProp['fromArray'])
|
|
444
|
-
targetProp['fromArray'](value);
|
|
445
|
-
else
|
|
446
|
-
targetProp['set'](...value);
|
|
447
|
-
}
|
|
448
|
-
// test again target.copy
|
|
449
|
-
else if (targetProp['copy'] &&
|
|
450
|
-
value &&
|
|
451
|
-
value.constructor &&
|
|
452
|
-
targetProp.constructor.name === value.constructor.name) {
|
|
453
|
-
targetProp['copy'](value);
|
|
454
|
-
if (!THREE.ColorManagement && !rootState.linear && isColor)
|
|
455
|
-
targetProp['convertSRGBToLinear']();
|
|
456
|
-
}
|
|
457
|
-
// if nothing else fits, just set the single value, ignore undefined
|
|
458
|
-
else if (value !== undefined) {
|
|
459
|
-
const isColor = targetProp instanceof THREE.Color;
|
|
460
|
-
// allow setting array scalars
|
|
461
|
-
if (!isColor && targetProp['setScalar'])
|
|
462
|
-
targetProp['setScalar'](value);
|
|
463
|
-
// layers have no copy function, copy the mask
|
|
464
|
-
else if (targetProp instanceof THREE.Layers && value instanceof THREE.Layers)
|
|
465
|
-
targetProp.mask = value.mask;
|
|
466
|
-
// otherwise just set ...
|
|
467
|
-
else
|
|
468
|
-
targetProp['set'](value);
|
|
469
|
-
// auto-convert srgb
|
|
470
|
-
if (!THREE.ColorManagement && !rootState?.linear && isColor)
|
|
471
|
-
targetProp.convertSRGBToLinear();
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
// else just overwrite the value
|
|
475
|
-
else {
|
|
476
|
-
currentInstance[key] = value;
|
|
477
|
-
// auto-convert srgb textures
|
|
478
|
-
if (currentInstance[key] instanceof THREE.Texture &&
|
|
479
|
-
currentInstance[key].format === THREE.RGBAFormat &&
|
|
480
|
-
currentInstance[key].type === THREE.UnsignedByteType) {
|
|
481
|
-
const texture = currentInstance[key];
|
|
482
|
-
if (is.colorSpaceExist(texture) && is.colorSpaceExist(rootState.gl))
|
|
483
|
-
texture.colorSpace = rootState.gl.outputColorSpace;
|
|
484
|
-
else
|
|
485
|
-
texture.encoding = rootState.gl.outputEncoding;
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
checkUpdate(targetProp);
|
|
489
|
-
invalidateInstance(instance);
|
|
490
|
-
}
|
|
491
|
-
const instanceHandlers = localState.eventCount;
|
|
492
|
-
if (localState.parent && rootState.internal && instance['raycast'] && instanceHandlers !== localState.eventCount) {
|
|
493
|
-
// pre-emptively remove the interaction from manager
|
|
494
|
-
rootState.removeInteraction(instance['uuid']);
|
|
495
|
-
// add the instance to the interaction manager only when it has handlers
|
|
496
|
-
if (localState.eventCount)
|
|
497
|
-
rootState.addInteraction(instance);
|
|
498
|
-
}
|
|
499
|
-
if (localState.parent && localState.afterUpdate && localState.afterUpdate.observed && changes.length) {
|
|
500
|
-
localState.afterUpdate.emit(instance);
|
|
501
|
-
}
|
|
502
|
-
return instance;
|
|
163
|
+
function makeDpr(dpr, window) {
|
|
164
|
+
const target = window?.devicePixelRatio || 1;
|
|
165
|
+
return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], target), dpr[1]) : dpr;
|
|
503
166
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
* addListener('event', cb);
|
|
520
|
-
*
|
|
521
|
-
* return () => {
|
|
522
|
-
* removeListener('event', cb);
|
|
523
|
-
* }
|
|
524
|
-
* })
|
|
525
|
-
* )
|
|
526
|
-
* ```
|
|
527
|
-
*/
|
|
528
|
-
function tapEffect(effectFn) {
|
|
529
|
-
let cleanupFn = () => { };
|
|
530
|
-
let firstRun = false;
|
|
531
|
-
let prev = undefined;
|
|
532
|
-
const teardown = (error) => () => {
|
|
533
|
-
if (cleanupFn)
|
|
534
|
-
cleanupFn({ prev, complete: true, error });
|
|
535
|
-
};
|
|
536
|
-
return tap({
|
|
537
|
-
next: (value) => {
|
|
538
|
-
if (cleanupFn && firstRun)
|
|
539
|
-
cleanupFn({ prev, complete: false, error: false });
|
|
540
|
-
const cleanUpOrVoid = effectFn(value);
|
|
541
|
-
if (cleanUpOrVoid)
|
|
542
|
-
cleanupFn = cleanUpOrVoid;
|
|
543
|
-
prev = value;
|
|
544
|
-
if (!firstRun)
|
|
545
|
-
firstRun = true;
|
|
546
|
-
},
|
|
547
|
-
complete: teardown(false),
|
|
548
|
-
unsubscribe: teardown(false),
|
|
549
|
-
error: teardown(true),
|
|
167
|
+
function makeDefaultCamera(isOrthographic, size) {
|
|
168
|
+
if (isOrthographic)
|
|
169
|
+
return new THREE.OrthographicCamera(0, 0, 0, 0, 0.1, 1000);
|
|
170
|
+
return new THREE.PerspectiveCamera(75, size.width / size.height, 0.1, 1000);
|
|
171
|
+
}
|
|
172
|
+
function makeDefaultRenderer(glOptions, canvasElement) {
|
|
173
|
+
const customRenderer = (typeof glOptions === 'function' ? glOptions(canvasElement) : glOptions);
|
|
174
|
+
if (customRenderer?.render != null)
|
|
175
|
+
return customRenderer;
|
|
176
|
+
return new THREE.WebGLRenderer({
|
|
177
|
+
powerPreference: 'high-performance',
|
|
178
|
+
canvas: canvasElement,
|
|
179
|
+
antialias: true,
|
|
180
|
+
alpha: true,
|
|
181
|
+
...(glOptions || {}),
|
|
550
182
|
});
|
|
551
183
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
const firstArg = args[0];
|
|
563
|
-
if (is.obj(firstArg)) {
|
|
564
|
-
const modArgs = Object.entries(firstArg).reduce((modded, [key, value]) => {
|
|
565
|
-
modded[key] = value === undefined ? this.get(key) : value;
|
|
566
|
-
return modded;
|
|
567
|
-
}, {});
|
|
568
|
-
return originalSet(modArgs);
|
|
569
|
-
}
|
|
570
|
-
return originalSet(...args);
|
|
571
|
-
};
|
|
572
|
-
},
|
|
573
|
-
});
|
|
574
|
-
// override get to return {} if get() returns undefined
|
|
575
|
-
const originalGet = this.get.bind(this);
|
|
576
|
-
Object.defineProperty(this, 'get', {
|
|
577
|
-
get: () => (...args) => {
|
|
578
|
-
if (args.length === 0)
|
|
579
|
-
return originalGet() ?? {};
|
|
580
|
-
return originalGet(...args);
|
|
581
|
-
},
|
|
184
|
+
function makeObjectGraph(object) {
|
|
185
|
+
const data = { nodes: {}, materials: {} };
|
|
186
|
+
if (object) {
|
|
187
|
+
object.traverse((child) => {
|
|
188
|
+
if (child.name)
|
|
189
|
+
data.nodes[child.name] = child;
|
|
190
|
+
if ('material' in child && !data.materials[child.material.name]) {
|
|
191
|
+
data.materials[child.material.name] = child
|
|
192
|
+
.material;
|
|
193
|
+
}
|
|
582
194
|
});
|
|
583
|
-
// call initialize that might be setup by derived Stores
|
|
584
|
-
this.initialize();
|
|
585
195
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
196
|
+
return data;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
|
|
200
|
+
const captureData = captures.get(obj);
|
|
201
|
+
if (captureData) {
|
|
202
|
+
captures.delete(obj);
|
|
203
|
+
// if this was the last captured object for this pointer
|
|
204
|
+
if (captures.size === 0) {
|
|
205
|
+
capturedMap.delete(pointerId);
|
|
206
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
207
|
+
}
|
|
591
208
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
209
|
+
}
|
|
210
|
+
function removeInteractivity(store, object) {
|
|
211
|
+
const internal = store.get('internal');
|
|
212
|
+
// removes every trace of an object from data store
|
|
213
|
+
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
214
|
+
internal.initialHits = internal.initialHits.filter((o) => o !== object);
|
|
215
|
+
internal.hovered.forEach((value, key) => {
|
|
216
|
+
if (value.eventObject === object || value.object === object) {
|
|
217
|
+
// clear out intersects, they are outdated by now
|
|
218
|
+
internal.hovered.delete(key);
|
|
596
219
|
}
|
|
597
|
-
|
|
220
|
+
});
|
|
221
|
+
internal.capturedMap.forEach((captures, pointerId) => {
|
|
222
|
+
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
223
|
+
});
|
|
224
|
+
if (store.get('previousStore')) {
|
|
225
|
+
removeInteractivity(store.get('previousStore'), object);
|
|
598
226
|
}
|
|
599
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRxStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
600
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRxStore }); }
|
|
601
227
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
const
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
class NgtStore extends NgtRxStore {
|
|
610
|
-
constructor() {
|
|
611
|
-
super(...arguments);
|
|
612
|
-
this.parentStore = inject(NgtStore, { optional: true, skipSelf: true });
|
|
613
|
-
this.window = inject(DOCUMENT).defaultView;
|
|
614
|
-
this.isInit = false;
|
|
228
|
+
function createEvents(store) {
|
|
229
|
+
/** calculates delta **/
|
|
230
|
+
function calculateDistance(event) {
|
|
231
|
+
const internal = store.get('internal');
|
|
232
|
+
const dx = event.offsetX - internal.initialClick[0];
|
|
233
|
+
const dy = event.offsetY - internal.initialClick[1];
|
|
234
|
+
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
615
235
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
const
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
236
|
+
/** returns true if an instance has a valid pointer-event registered, this excludes scroll, clicks etc... **/
|
|
237
|
+
function filterPointerEvents(objects) {
|
|
238
|
+
return objects.filter((obj) => ['move', 'over', 'enter', 'out', 'leave'].some((name) => {
|
|
239
|
+
const eventName = `pointer${name}`;
|
|
240
|
+
return getLocalState(obj).handlers?.[eventName];
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
function intersect(event, filter) {
|
|
244
|
+
const state = store.get();
|
|
245
|
+
const duplicates = new Set();
|
|
246
|
+
const intersections = [];
|
|
247
|
+
// allow callers to eliminate event objects
|
|
248
|
+
const eventObjects = filter ? filter(state.internal.interaction) : state.internal.interaction;
|
|
249
|
+
// reset all raycaster cameras to undefined
|
|
250
|
+
for (let i = 0; i < eventObjects.length; i++) {
|
|
251
|
+
const instanceState = getLocalState(eventObjects[i]).store?.get();
|
|
252
|
+
if (instanceState) {
|
|
253
|
+
instanceState.raycaster.camera = undefined;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (!state.previousStore) {
|
|
257
|
+
// make sure root-level pointer and ray are setup
|
|
258
|
+
state.events.compute?.(event, store);
|
|
259
|
+
}
|
|
260
|
+
function handleRaycast(obj) {
|
|
261
|
+
const objLocalState = getLocalState(obj);
|
|
262
|
+
const objStore = objLocalState.store;
|
|
263
|
+
const objState = objStore?.get();
|
|
264
|
+
// skip event handling when noEvents is set, or when raycaster camera is null
|
|
265
|
+
if (!objState || !objState.events.enabled || objState.raycaster.camera === null)
|
|
266
|
+
return [];
|
|
267
|
+
// when the camera is undefined, we have to call the events layers to update function
|
|
268
|
+
if (objState.raycaster.camera === undefined) {
|
|
269
|
+
objState.events.compute?.(event, objStore, objState.previousStore);
|
|
270
|
+
// if the camera is still undefined, we have to skip this layer entirely
|
|
271
|
+
if (objState.raycaster.camera === undefined)
|
|
272
|
+
objState.raycaster.camera = null;
|
|
273
|
+
}
|
|
274
|
+
// intersect object by object
|
|
275
|
+
return objState.raycaster.camera ? objState.raycaster.intersectObject(obj, true) : [];
|
|
276
|
+
}
|
|
277
|
+
// collect events
|
|
278
|
+
let hits = eventObjects
|
|
279
|
+
// intersect objects
|
|
280
|
+
.flatMap(handleRaycast)
|
|
281
|
+
// sort by event priority
|
|
282
|
+
.sort((a, b) => {
|
|
283
|
+
const aState = getLocalState(a.object).store.get();
|
|
284
|
+
const bState = getLocalState(b.object).store.get();
|
|
285
|
+
if (!aState || !bState)
|
|
286
|
+
return a.distance - b.distance;
|
|
287
|
+
return bState.events.priority - aState.events.priority || a.distance - b.distance;
|
|
288
|
+
})
|
|
289
|
+
// filter out duplicates
|
|
290
|
+
.filter((item) => {
|
|
291
|
+
const id = makeId(item);
|
|
292
|
+
if (duplicates.has(id))
|
|
293
|
+
return false;
|
|
294
|
+
duplicates.add(id);
|
|
295
|
+
return true;
|
|
296
|
+
});
|
|
297
|
+
// allow custom userland intersect sort order, this likely only makes sense on the root
|
|
298
|
+
if (state.events.filter)
|
|
299
|
+
hits = state.events.filter(hits, store);
|
|
300
|
+
// bubble up the events, find the event source
|
|
301
|
+
for (const hit of hits) {
|
|
302
|
+
let eventObject = hit.object;
|
|
303
|
+
// bubble event up
|
|
304
|
+
while (eventObject) {
|
|
305
|
+
if (getLocalState(eventObject).eventCount) {
|
|
306
|
+
intersections.push({ ...hit, eventObject });
|
|
639
307
|
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
//
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
// Decrease manual flag if this subscription had a priority
|
|
723
|
-
internal.priority = internal.priority - (priority > 0 ? 1 : 0);
|
|
724
|
-
// Remove subscriber from list
|
|
725
|
-
internal.subscribers = internal.subscribers.filter((s) => s.callback !== callback);
|
|
308
|
+
eventObject = eventObject.parent;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// if the interaction is captured, make all capturing targets part of the intersects
|
|
312
|
+
if ('pointerId' in event && state.internal.capturedMap.has(event.pointerId)) {
|
|
313
|
+
for (const capturedData of state.internal.capturedMap.get(event.pointerId).values()) {
|
|
314
|
+
if (!duplicates.has(makeId(capturedData.intersection))) {
|
|
315
|
+
intersections.push(capturedData.intersection);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return intersections;
|
|
320
|
+
}
|
|
321
|
+
/** handle intersections by forwarding them to handlers */
|
|
322
|
+
function handleIntersects(intersections, event, delta, callback) {
|
|
323
|
+
const rootState = store.get();
|
|
324
|
+
// if anything has been found, forward it to the event listeners
|
|
325
|
+
if (intersections.length) {
|
|
326
|
+
const localState = { stopped: false };
|
|
327
|
+
for (const hit of intersections) {
|
|
328
|
+
const state = getLocalState(hit.object).store?.get() || rootState;
|
|
329
|
+
const { raycaster, pointer, camera, internal } = state;
|
|
330
|
+
const unprojectedPoint = new THREE.Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
331
|
+
const hasPointerCapture = (id) => internal.capturedMap.get(id)?.has(hit.eventObject) ?? false;
|
|
332
|
+
const setPointerCapture = (id) => {
|
|
333
|
+
const captureData = { intersection: hit, target: event.target };
|
|
334
|
+
if (internal.capturedMap.has(id)) {
|
|
335
|
+
// if the pointerId was previously captured, we add the hit to the event capturedMap
|
|
336
|
+
internal.capturedMap.get(id).set(hit.eventObject, captureData);
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
// if the pointerId was not previously captured, we create a Map containing the hitObject, and the hit. hitObject is used for faster access
|
|
340
|
+
internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
|
|
341
|
+
}
|
|
342
|
+
// call the original event now
|
|
343
|
+
event.target.setPointerCapture(id);
|
|
344
|
+
};
|
|
345
|
+
const releasePointerCapture = (id) => {
|
|
346
|
+
const captures = internal.capturedMap.get(id);
|
|
347
|
+
if (captures) {
|
|
348
|
+
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
// add native event props
|
|
352
|
+
const extractEventProps = {};
|
|
353
|
+
// This iterates over the event's properties including the inherited ones. Native PointerEvents have most of their props as getters which are inherited, but polyfilled PointerEvents have them all as their own properties (i.e. not inherited). We can't use Object.keys() or Object.entries() as they only return "own" properties; nor Object.getPrototypeOf(event) as that *doesn't* return "own" properties, only inherited ones.
|
|
354
|
+
for (const prop in event) {
|
|
355
|
+
const property = event[prop];
|
|
356
|
+
// only copy over atomics, leave functions alone as these should be called as event.nativeEvent.fn()
|
|
357
|
+
if (typeof property !== 'function') {
|
|
358
|
+
extractEventProps[prop] = property;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const raycastEvent = {
|
|
362
|
+
...hit,
|
|
363
|
+
...extractEventProps,
|
|
364
|
+
pointer,
|
|
365
|
+
intersections,
|
|
366
|
+
stopped: localState.stopped,
|
|
367
|
+
delta,
|
|
368
|
+
unprojectedPoint,
|
|
369
|
+
ray: raycaster.ray,
|
|
370
|
+
camera: camera,
|
|
371
|
+
// Hijack stopPropagation, which just sets a flag
|
|
372
|
+
stopPropagation() {
|
|
373
|
+
// https://github.com/pmndrs/react-three-fiber/issues/596
|
|
374
|
+
// Events are not allowed to stop propagation if the pointer has been captured
|
|
375
|
+
const capturesForPointer = 'pointerId' in event && internal.capturedMap.get(event.pointerId);
|
|
376
|
+
// We only authorize stopPropagation...
|
|
377
|
+
if (
|
|
378
|
+
// ...if this pointer hasn't been captured
|
|
379
|
+
!capturesForPointer ||
|
|
380
|
+
// ... or if the hit object is capturing the pointer
|
|
381
|
+
capturesForPointer.has(hit.eventObject)) {
|
|
382
|
+
raycastEvent.stopped = localState.stopped = true;
|
|
383
|
+
// Propagation is stopped, remove all other hover records
|
|
384
|
+
// An event handler is only allowed to flush other handlers if it is hovered itself
|
|
385
|
+
if (internal.hovered.size &&
|
|
386
|
+
Array.from(internal.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
387
|
+
// Objects cannot flush out higher up objects that have already caught the event
|
|
388
|
+
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
389
|
+
cancelPointer([...higher, hit]);
|
|
726
390
|
}
|
|
727
|
-
}
|
|
391
|
+
}
|
|
728
392
|
},
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
393
|
+
// there should be a distinction between target and currentTarget
|
|
394
|
+
target: { hasPointerCapture, setPointerCapture, releasePointerCapture },
|
|
395
|
+
currentTarget: { hasPointerCapture, setPointerCapture, releasePointerCapture },
|
|
396
|
+
nativeEvent: event,
|
|
397
|
+
};
|
|
398
|
+
// call subscribers
|
|
399
|
+
callback(raycastEvent);
|
|
400
|
+
// event bubbling may be interupted by stopPropagation
|
|
401
|
+
if (localState.stopped === true)
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return intersections;
|
|
406
|
+
}
|
|
407
|
+
function cancelPointer(intersections) {
|
|
408
|
+
const { internal } = store.get();
|
|
409
|
+
for (const hoveredObj of internal.hovered.values()) {
|
|
410
|
+
// When no objects were hit or the hovered object wasn't found underneath the cursor
|
|
411
|
+
// we call onPointerOut and delete the object from the hovered-elements map
|
|
412
|
+
if (!intersections.length ||
|
|
413
|
+
!intersections.find((hit) => hit.object === hoveredObj.object &&
|
|
414
|
+
hit.index === hoveredObj.index &&
|
|
415
|
+
hit.instanceId === hoveredObj.instanceId)) {
|
|
416
|
+
const eventObject = hoveredObj.eventObject;
|
|
417
|
+
const instance = getLocalState(eventObject);
|
|
418
|
+
const handlers = instance?.handlers;
|
|
419
|
+
internal.hovered.delete(makeId(hoveredObj));
|
|
420
|
+
if (instance?.eventCount) {
|
|
421
|
+
// Clear out intersects, they are outdated by now
|
|
422
|
+
const data = { ...hoveredObj, intersections };
|
|
423
|
+
handlers?.pointerout?.(data);
|
|
424
|
+
handlers?.pointerleave?.(data);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function pointerMissed(event, objects) {
|
|
430
|
+
for (let i = 0; i < objects.length; i++) {
|
|
431
|
+
const instance = getLocalState(objects[i]);
|
|
432
|
+
instance?.handlers.pointermissed?.(event);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function handlePointer(name) {
|
|
436
|
+
// Deal with cancelation
|
|
437
|
+
switch (name) {
|
|
438
|
+
case 'pointerleave':
|
|
439
|
+
case 'pointercancel':
|
|
440
|
+
return () => cancelPointer([]);
|
|
441
|
+
case 'lostpointercapture':
|
|
442
|
+
return (event) => {
|
|
443
|
+
const { internal } = store.get();
|
|
444
|
+
if ('pointerId' in event && internal.capturedMap.has(event.pointerId)) {
|
|
445
|
+
// If the object event interface had onLostPointerCapture, we'd call it here on every
|
|
446
|
+
// object that's getting removed.
|
|
447
|
+
internal.capturedMap.delete(event.pointerId);
|
|
448
|
+
cancelPointer([]);
|
|
758
449
|
}
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
// Any other pointer goes here ...
|
|
453
|
+
return function handleEvent(event) {
|
|
454
|
+
const { onPointerMissed, internal } = store.get();
|
|
455
|
+
// prepareRay(event)
|
|
456
|
+
internal.lastEvent.nativeElement = event;
|
|
457
|
+
// Get fresh intersects
|
|
458
|
+
const isPointerMove = name === 'pointermove';
|
|
459
|
+
const isClickEvent = name === 'click' || name === 'contextmenu' || name === 'dblclick';
|
|
460
|
+
const filter = isPointerMove ? filterPointerEvents : undefined;
|
|
461
|
+
// const hits = patchIntersects(intersect(filter), event)
|
|
462
|
+
const hits = intersect(event, filter);
|
|
463
|
+
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
464
|
+
// Save initial coordinates on pointer-down
|
|
465
|
+
if (name === 'pointerdown') {
|
|
466
|
+
internal.initialClick = [event.offsetX, event.offsetY];
|
|
467
|
+
internal.initialHits = hits.map((hit) => hit.eventObject);
|
|
468
|
+
}
|
|
469
|
+
// If a click yields no results, pass it back to the user as a miss
|
|
470
|
+
// Missed events have to come first in order to establish user-land side-effect clean up
|
|
471
|
+
if (isClickEvent && !hits.length) {
|
|
472
|
+
if (delta <= 2) {
|
|
473
|
+
pointerMissed(event, internal.interaction);
|
|
474
|
+
if (onPointerMissed)
|
|
475
|
+
onPointerMissed(event);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
// Take care of unhover
|
|
479
|
+
if (isPointerMove)
|
|
480
|
+
cancelPointer(hits);
|
|
481
|
+
function onIntersect(data) {
|
|
482
|
+
const eventObject = data.eventObject;
|
|
483
|
+
const instance = getLocalState(eventObject);
|
|
484
|
+
const handlers = instance?.handlers;
|
|
485
|
+
// Check presence of handlers
|
|
486
|
+
if (!instance?.eventCount)
|
|
487
|
+
return;
|
|
488
|
+
if (isPointerMove) {
|
|
489
|
+
// Move event ...
|
|
490
|
+
if (handlers?.pointerover ||
|
|
491
|
+
handlers?.pointerenter ||
|
|
492
|
+
handlers?.pointerout ||
|
|
493
|
+
handlers?.pointerleave) {
|
|
494
|
+
// When enter or out is present take care of hover-state
|
|
495
|
+
const id = makeId(data);
|
|
496
|
+
const hoveredItem = internal.hovered.get(id);
|
|
497
|
+
if (!hoveredItem) {
|
|
498
|
+
// If the object wasn't previously hovered, book it and call its handler
|
|
499
|
+
internal.hovered.set(id, data);
|
|
500
|
+
handlers.pointerover?.(data);
|
|
501
|
+
handlers.pointerenter?.(data);
|
|
502
|
+
}
|
|
503
|
+
else if (hoveredItem.stopped) {
|
|
504
|
+
// If the object was previously hovered and stopped, we shouldn't allow other items to proceed
|
|
505
|
+
data.stopPropagation();
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
// Call mouse move
|
|
509
|
+
handlers?.pointermove?.(data);
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
// All other events ...
|
|
513
|
+
const handler = handlers?.[name];
|
|
514
|
+
if (handler) {
|
|
515
|
+
// Forward all events back to their respective handlers with the exception of click events,
|
|
516
|
+
// which must use the initial target
|
|
517
|
+
if (!isClickEvent || internal.initialHits.includes(eventObject)) {
|
|
518
|
+
// Missed events have to come first
|
|
519
|
+
pointerMissed(event, internal.interaction.filter((object) => !internal.initialHits.includes(object)));
|
|
520
|
+
// Now call the handler
|
|
521
|
+
handler(data);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
// Trigger onPointerMissed on all elements that have pointer over/out handlers, but not click and weren't hit
|
|
526
|
+
if (isClickEvent && internal.initialHits.includes(eventObject)) {
|
|
527
|
+
pointerMissed(event, internal.interaction.filter((object) => !internal.initialHits.includes(object)));
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
handleIntersects(hits, event, delta, onIntersect);
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
return { handlePointer };
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const DOM_EVENTS = {
|
|
539
|
+
click: false,
|
|
540
|
+
contextmenu: false,
|
|
541
|
+
dblclick: false,
|
|
542
|
+
wheel: false,
|
|
543
|
+
pointerdown: true,
|
|
544
|
+
pointerup: true,
|
|
545
|
+
pointerleave: true,
|
|
546
|
+
pointermove: true,
|
|
547
|
+
pointercancel: true,
|
|
548
|
+
lostpointercapture: true,
|
|
549
|
+
};
|
|
550
|
+
const supportedEvents = [
|
|
551
|
+
'click',
|
|
552
|
+
'contextmenu',
|
|
553
|
+
'dblclick',
|
|
554
|
+
'pointerup',
|
|
555
|
+
'pointerdown',
|
|
556
|
+
'pointerover',
|
|
557
|
+
'pointerout',
|
|
558
|
+
'pointerenter',
|
|
559
|
+
'pointerleave',
|
|
560
|
+
'pointermove',
|
|
561
|
+
'pointermissed',
|
|
562
|
+
'pointercancel',
|
|
563
|
+
'wheel',
|
|
564
|
+
];
|
|
565
|
+
function createPointerEvents(store) {
|
|
566
|
+
const { handlePointer } = createEvents(store);
|
|
567
|
+
return {
|
|
568
|
+
priority: 1,
|
|
569
|
+
enabled: true,
|
|
570
|
+
compute: (event, root) => {
|
|
571
|
+
const state = root.get();
|
|
572
|
+
// https://github.com/pmndrs/react-three-fiber/pull/782
|
|
573
|
+
// Events trigger outside of canvas when moved, use offsetX/Y by default and allow overrides
|
|
574
|
+
state.pointer.set((event.offsetX / state.size.width) * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
575
|
+
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
576
|
+
},
|
|
577
|
+
connected: undefined,
|
|
578
|
+
handlers: Object.keys(DOM_EVENTS).reduce((handlers, supportedEventName) => {
|
|
579
|
+
handlers[supportedEventName] = handlePointer(supportedEventName);
|
|
580
|
+
return handlers;
|
|
581
|
+
}, {}),
|
|
582
|
+
connect: (target) => {
|
|
583
|
+
const state = store.get();
|
|
584
|
+
state.events.disconnect?.();
|
|
585
|
+
state.setEvents({ connected: target });
|
|
586
|
+
Object.entries(state.events.handlers ?? {}).forEach(([eventName, eventHandler]) => {
|
|
587
|
+
const passive = DOM_EVENTS[eventName];
|
|
588
|
+
target.addEventListener(eventName, eventHandler, { passive });
|
|
774
589
|
});
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
if (!state.gl)
|
|
786
|
-
stateToUpdate.gl = gl = makeDefaultRenderer(glOptions, canvasElement);
|
|
787
|
-
// setup raycaster
|
|
788
|
-
let raycaster = state.raycaster;
|
|
789
|
-
if (!raycaster)
|
|
790
|
-
stateToUpdate.raycaster = raycaster = new THREE.Raycaster();
|
|
791
|
-
// set raycaster options
|
|
792
|
-
const { params, ...options } = raycasterOptions || {};
|
|
793
|
-
if (!is.equ(options, raycaster, shallowLoose))
|
|
794
|
-
applyProps(raycaster, { ...options });
|
|
795
|
-
if (!is.equ(params, raycaster.params, shallowLoose)) {
|
|
796
|
-
applyProps(raycaster, { params: { ...raycaster.params, ...(params || {}) } });
|
|
797
|
-
}
|
|
798
|
-
// create default camera
|
|
799
|
-
if (!state.camera) {
|
|
800
|
-
const isCamera = is.camera(cameraOptions);
|
|
801
|
-
let camera = isCamera ? cameraOptions : makeDefaultCamera(orthographic || false, state.size);
|
|
802
|
-
if (!isCamera) {
|
|
803
|
-
if (cameraOptions)
|
|
804
|
-
applyProps(camera, cameraOptions);
|
|
805
|
-
// set position.z
|
|
806
|
-
if (!cameraOptions?.position)
|
|
807
|
-
camera.position.z = 5;
|
|
808
|
-
// always look at center or passed-in lookAt by default
|
|
809
|
-
if (!cameraOptions?.rotation) {
|
|
810
|
-
if (Array.isArray(lookAt))
|
|
811
|
-
camera.lookAt(lookAt[0], lookAt[1], lookAt[2]);
|
|
812
|
-
else if (lookAt instanceof THREE.Vector3)
|
|
813
|
-
camera.lookAt(lookAt);
|
|
814
|
-
else
|
|
815
|
-
camera.lookAt(0, 0, 0);
|
|
816
|
-
}
|
|
817
|
-
// update projection matrix after applyprops
|
|
818
|
-
camera.updateProjectionMatrix?.();
|
|
819
|
-
}
|
|
820
|
-
if (!is.instance(camera))
|
|
821
|
-
camera = prepare(camera, { store: this });
|
|
822
|
-
stateToUpdate.camera = camera;
|
|
823
|
-
}
|
|
824
|
-
// Set up XR (one time only!)
|
|
825
|
-
if (!state.xr) {
|
|
826
|
-
// Handle frame behavior in WebXR
|
|
827
|
-
const handleXRFrame = (timestamp, frame) => {
|
|
828
|
-
const state = this.get();
|
|
829
|
-
if (state.frameloop === 'never')
|
|
830
|
-
return;
|
|
831
|
-
advance(timestamp, true, this, frame);
|
|
832
|
-
};
|
|
833
|
-
// Toggle render switching on session
|
|
834
|
-
const handleSessionChange = () => {
|
|
835
|
-
const state = this.get();
|
|
836
|
-
state.gl.xr.enabled = state.gl.xr.isPresenting;
|
|
837
|
-
state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
|
|
838
|
-
if (!state.gl.xr.isPresenting)
|
|
839
|
-
invalidate(this);
|
|
840
|
-
};
|
|
841
|
-
// WebXR session manager
|
|
842
|
-
const xr = {
|
|
843
|
-
connect: () => {
|
|
844
|
-
gl.xr.addEventListener('sessionstart', handleSessionChange);
|
|
845
|
-
gl.xr.addEventListener('sessionend', handleSessionChange);
|
|
846
|
-
},
|
|
847
|
-
disconnect: () => {
|
|
848
|
-
gl.xr.removeEventListener('sessionstart', handleSessionChange);
|
|
849
|
-
gl.xr.removeEventListener('sessionend', handleSessionChange);
|
|
850
|
-
},
|
|
851
|
-
};
|
|
852
|
-
// Subscribe to WebXR session events
|
|
853
|
-
if (gl.xr)
|
|
854
|
-
xr.connect();
|
|
855
|
-
stateToUpdate.xr = xr;
|
|
856
|
-
}
|
|
857
|
-
// Set shadowmap
|
|
858
|
-
if (gl.shadowMap) {
|
|
859
|
-
const isBoolean = typeof shadows === 'boolean';
|
|
860
|
-
if ((isBoolean && gl.shadowMap.enabled !== shadows) || !is.equ(shadows, gl.shadowMap, shallowLoose)) {
|
|
861
|
-
const old = gl.shadowMap.enabled;
|
|
862
|
-
gl.shadowMap.enabled = !!shadows;
|
|
863
|
-
if (!isBoolean)
|
|
864
|
-
Object.assign(gl.shadowMap, shadows);
|
|
865
|
-
else
|
|
866
|
-
gl.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
867
|
-
if (old !== gl.shadowMap.enabled)
|
|
868
|
-
checkNeedsUpdate(gl.shadowMap);
|
|
590
|
+
},
|
|
591
|
+
disconnect: () => {
|
|
592
|
+
const { events, setEvents } = store.get();
|
|
593
|
+
if (events.connected) {
|
|
594
|
+
Object.entries(events.handlers ?? {}).forEach(([eventName, eventHandler]) => {
|
|
595
|
+
if (events.connected instanceof HTMLElement) {
|
|
596
|
+
events.connected.removeEventListener(eventName, eventHandler);
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
setEvents({ connected: undefined });
|
|
869
600
|
}
|
|
601
|
+
},
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
function safeDetectChanges(cdr) {
|
|
606
|
+
if (!cdr)
|
|
607
|
+
return;
|
|
608
|
+
try {
|
|
609
|
+
// dynamic created component with ViewContainerRef#createComponent does not have Context
|
|
610
|
+
// but it has _attachedToViewContainer
|
|
611
|
+
if (cdr['context'] || cdr['_attachedToViewContainer']) {
|
|
612
|
+
cdr.detectChanges();
|
|
870
613
|
}
|
|
871
|
-
// Safely set color management if available.
|
|
872
|
-
// Avoid accessing THREE.ColorManagement to play nice with older versions
|
|
873
|
-
if (THREE.ColorManagement) {
|
|
874
|
-
const ColorManagement = THREE.ColorManagement;
|
|
875
|
-
if ('enabled' in ColorManagement)
|
|
876
|
-
ColorManagement['enabled'] = !legacy ?? false;
|
|
877
|
-
else if ('legacyMode' in ColorManagement)
|
|
878
|
-
ColorManagement['legacyMode'] = legacy ?? true;
|
|
879
|
-
}
|
|
880
|
-
// set color space and tonemapping preferences
|
|
881
|
-
const LinearEncoding = 3000;
|
|
882
|
-
const sRGBEncoding = 3001;
|
|
883
|
-
applyProps(gl, {
|
|
884
|
-
outputEncoding: linear ? LinearEncoding : sRGBEncoding,
|
|
885
|
-
toneMapping: flat ? THREE.NoToneMapping : THREE.ACESFilmicToneMapping,
|
|
886
|
-
});
|
|
887
|
-
// Update color management state
|
|
888
|
-
if (state.legacy !== legacy)
|
|
889
|
-
stateToUpdate.legacy = legacy;
|
|
890
|
-
if (state.linear !== linear)
|
|
891
|
-
stateToUpdate.linear = linear;
|
|
892
|
-
if (state.flat !== flat)
|
|
893
|
-
stateToUpdate.flat = flat;
|
|
894
|
-
// Set gl props
|
|
895
|
-
gl.setClearAlpha(0);
|
|
896
|
-
gl.setPixelRatio(makeDpr(state.viewport.dpr));
|
|
897
|
-
gl.setSize(state.size.width, state.size.height);
|
|
898
|
-
if (is.obj(glOptions) &&
|
|
899
|
-
!(typeof glOptions === 'function') &&
|
|
900
|
-
!is.renderer(glOptions) &&
|
|
901
|
-
!is.equ(glOptions, gl, shallowLoose)) {
|
|
902
|
-
applyProps(gl, glOptions);
|
|
903
|
-
}
|
|
904
|
-
// Store events internally
|
|
905
|
-
if (events && !state.events.handlers)
|
|
906
|
-
stateToUpdate.events = events(this);
|
|
907
|
-
// Check performance
|
|
908
|
-
if (performance && !is.equ(performance, state.performance, shallowLoose)) {
|
|
909
|
-
stateToUpdate.performance = { ...state.performance, ...performance };
|
|
910
|
-
}
|
|
911
|
-
this.set(stateToUpdate);
|
|
912
|
-
// Check pixelratio
|
|
913
|
-
if (dpr && state.viewport.dpr !== makeDpr(dpr))
|
|
914
|
-
state.setDpr(dpr);
|
|
915
|
-
// Check size, allow it to take on container bounds initially
|
|
916
|
-
const size = computeInitialSize(canvasElement, sizeOptions);
|
|
917
|
-
if (!is.equ(size, state.size, shallowLoose))
|
|
918
|
-
state.setSize(size.width, size.height, size.top, size.left);
|
|
919
|
-
// Check frameloop
|
|
920
|
-
if (state.frameloop !== frameloop)
|
|
921
|
-
state.setFrameloop(frameloop);
|
|
922
|
-
if (!this.get('ready'))
|
|
923
|
-
this.set({ ready: true });
|
|
924
|
-
this.invalidate();
|
|
925
614
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
setTimeout(() => {
|
|
929
|
-
const { gl, xr, events } = this.get();
|
|
930
|
-
if (gl) {
|
|
931
|
-
if (events.disconnect) {
|
|
932
|
-
events.disconnect();
|
|
933
|
-
}
|
|
934
|
-
gl.renderLists.dispose();
|
|
935
|
-
gl.forceContextLoss();
|
|
936
|
-
if (gl.xr && gl.xr.enabled) {
|
|
937
|
-
gl.xr.setAnimationLoop(null);
|
|
938
|
-
xr.disconnect();
|
|
939
|
-
}
|
|
940
|
-
dispose(this.get());
|
|
941
|
-
rootStateMap.delete(canvas);
|
|
942
|
-
}
|
|
943
|
-
}, 500);
|
|
615
|
+
catch (e) {
|
|
616
|
+
cdr.markForCheck();
|
|
944
617
|
}
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const cached = new Map();
|
|
621
|
+
function load(loaderConstructorFactory, inputs, { extensions, onProgress, } = {}) {
|
|
622
|
+
const computedUrls = computed(() => {
|
|
623
|
+
const input = inputs();
|
|
624
|
+
if (Array.isArray(input))
|
|
625
|
+
return input;
|
|
626
|
+
if (typeof input === 'string')
|
|
627
|
+
return [input];
|
|
628
|
+
return Object.values(input);
|
|
629
|
+
});
|
|
630
|
+
return () => {
|
|
631
|
+
const urls = computedUrls();
|
|
632
|
+
const loaderConstructor = loaderConstructorFactory(urls);
|
|
633
|
+
const loader = new loaderConstructor();
|
|
634
|
+
if (extensions)
|
|
635
|
+
extensions(loader);
|
|
636
|
+
return urls.map((url) => new Promise((resolve, reject) => {
|
|
637
|
+
if (cached.has(url)) {
|
|
638
|
+
resolve(cached.get(url));
|
|
959
639
|
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
}));
|
|
640
|
+
else {
|
|
641
|
+
loader.load(url, (data) => {
|
|
642
|
+
if ('scene' in data)
|
|
643
|
+
Object.assign(data, makeObjectGraph(data['scene']));
|
|
644
|
+
cached.set(url, data);
|
|
645
|
+
resolve(data);
|
|
646
|
+
}, onProgress, (error) => reject(new Error(`[NGT] Could not load ${url}: ${error}`)));
|
|
967
647
|
}
|
|
968
|
-
});
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
|
|
648
|
+
}));
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
function injectNgtLoader(loaderConstructorFactory, inputs, { extensions, onProgress, injector = inject(Injector, { optional: true }), } = {}) {
|
|
652
|
+
!injector && assertInInjectionContext(injectNgtLoader);
|
|
653
|
+
return runInInjectionContext(injector, () => {
|
|
654
|
+
const cdr = inject(ChangeDetectorRef);
|
|
655
|
+
const response = signal(null);
|
|
656
|
+
const effector = load(loaderConstructorFactory, inputs, { extensions, onProgress });
|
|
657
|
+
effect(() => {
|
|
658
|
+
const originalUrls = untracked(inputs);
|
|
659
|
+
Promise.all(effector())
|
|
660
|
+
.then((results) => {
|
|
661
|
+
if (Array.isArray(originalUrls))
|
|
662
|
+
return results;
|
|
663
|
+
if (typeof originalUrls === 'string')
|
|
664
|
+
return results[0];
|
|
665
|
+
const keys = Object.keys(originalUrls);
|
|
666
|
+
return keys.reduce((result, key) => {
|
|
667
|
+
result[key] = results[keys.indexOf(key)];
|
|
668
|
+
return result;
|
|
669
|
+
}, {});
|
|
670
|
+
})
|
|
671
|
+
.then((value) => {
|
|
672
|
+
response.set(value);
|
|
673
|
+
safeDetectChanges(cdr);
|
|
674
|
+
});
|
|
675
|
+
}, { injector: injector, allowSignalWrites: true });
|
|
676
|
+
return response.asReadonly();
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
injectNgtLoader['preload'] = (loaderConstructorFactory, inputs, extensions) => {
|
|
680
|
+
Promise.all(load(loaderConstructorFactory, inputs, { extensions })());
|
|
681
|
+
};
|
|
682
|
+
injectNgtLoader['destroy'] = () => {
|
|
683
|
+
cached.clear();
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
function createSubs(callback, subs) {
|
|
687
|
+
const sub = { callback };
|
|
688
|
+
subs.add(sub);
|
|
689
|
+
return () => void subs.delete(sub);
|
|
690
|
+
}
|
|
691
|
+
const globalEffects = new Set();
|
|
692
|
+
const globalAfterEffects = new Set();
|
|
693
|
+
const globalTailEffects = new Set();
|
|
694
|
+
/**
|
|
695
|
+
* Adds a global render callback which is called each frame.
|
|
696
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addEffect
|
|
697
|
+
*/
|
|
698
|
+
const addEffect = (callback) => createSubs(callback, globalEffects);
|
|
699
|
+
/**
|
|
700
|
+
* Adds a global after-render callback which is called each frame.
|
|
701
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addAfterEffect
|
|
702
|
+
*/
|
|
703
|
+
const addAfterEffect = (callback) => createSubs(callback, globalAfterEffects);
|
|
704
|
+
/**
|
|
705
|
+
* Adds a global callback which is called when rendering stops.
|
|
706
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addTail
|
|
707
|
+
*/
|
|
708
|
+
const addTail = (callback) => createSubs(callback, globalTailEffects);
|
|
709
|
+
function run(effects, timestamp) {
|
|
710
|
+
if (!effects.size)
|
|
711
|
+
return;
|
|
712
|
+
for (const { callback } of effects.values()) {
|
|
713
|
+
callback(timestamp);
|
|
972
714
|
}
|
|
973
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtStore, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
974
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtStore }); }
|
|
975
715
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
716
|
+
function flushGlobalEffects(type, timestamp) {
|
|
717
|
+
switch (type) {
|
|
718
|
+
case 'before':
|
|
719
|
+
return run(globalEffects, timestamp);
|
|
720
|
+
case 'after':
|
|
721
|
+
return run(globalAfterEffects, timestamp);
|
|
722
|
+
case 'tail':
|
|
723
|
+
return run(globalTailEffects, timestamp);
|
|
984
724
|
}
|
|
985
|
-
return { width: 0, height: 0, top: 0, left: 0 };
|
|
986
725
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
726
|
+
function render(timestamp, store, frame) {
|
|
727
|
+
const state = store.get();
|
|
728
|
+
// Run local effects
|
|
729
|
+
let delta = state.clock.getDelta();
|
|
730
|
+
// In frameloop='never' mode, clock times are updated using the provided timestamp
|
|
731
|
+
if (state.frameloop === 'never' && typeof timestamp === 'number') {
|
|
732
|
+
delta = timestamp - state.clock.elapsedTime;
|
|
733
|
+
state.clock.oldTime = state.clock.elapsedTime;
|
|
734
|
+
state.clock.elapsedTime = timestamp;
|
|
994
735
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
function extend(objects) {
|
|
1001
|
-
Object.assign(catalogue, objects);
|
|
1002
|
-
}
|
|
1003
|
-
const NGT_CATALOGUE = new InjectionToken('THREE Constructors Catalogue', { factory: () => catalogue });
|
|
1004
|
-
|
|
1005
|
-
class NgtCommonDirective {
|
|
1006
|
-
constructor() {
|
|
1007
|
-
this.vcr = inject(ViewContainerRef);
|
|
1008
|
-
this.template = inject(TemplateRef);
|
|
1009
|
-
this.injected = false;
|
|
1010
|
-
this.shouldCreateView = true;
|
|
1011
|
-
const commentNode = this.vcr.element.nativeElement;
|
|
1012
|
-
if (commentNode['__ngt_renderer_add_comment__']) {
|
|
1013
|
-
commentNode['__ngt_renderer_add_comment__']();
|
|
1014
|
-
delete commentNode['__ngt_renderer_add_comment__'];
|
|
1015
|
-
}
|
|
736
|
+
// Call subscribers (useFrame)
|
|
737
|
+
const subscribers = state.internal.subscribers;
|
|
738
|
+
for (let i = 0; i < subscribers.length; i++) {
|
|
739
|
+
const subscription = subscribers[i];
|
|
740
|
+
subscription.callback({ ...subscription.store.get(), delta, frame });
|
|
1016
741
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
742
|
+
// Render content
|
|
743
|
+
if (!state.internal.priority && state.gl.render)
|
|
744
|
+
state.gl.render(state.scene, state.camera);
|
|
745
|
+
// Decrease frame count
|
|
746
|
+
state.internal.frames = Math.max(0, state.internal.frames - 1);
|
|
747
|
+
return state.frameloop === 'always' ? 1 : state.internal.frames;
|
|
748
|
+
}
|
|
749
|
+
function createLoop(roots) {
|
|
750
|
+
let running = false;
|
|
751
|
+
let repeat;
|
|
752
|
+
let frame;
|
|
753
|
+
function loop(timestamp) {
|
|
754
|
+
frame = requestAnimationFrame(loop);
|
|
755
|
+
running = true;
|
|
756
|
+
repeat = 0;
|
|
757
|
+
// Run effects
|
|
758
|
+
flushGlobalEffects('before', timestamp);
|
|
759
|
+
// Render all roots
|
|
760
|
+
for (const root of roots.values()) {
|
|
761
|
+
const state = root.get();
|
|
762
|
+
// If the frameloop is invalidated, do not run another frame
|
|
763
|
+
if (state.internal.active &&
|
|
764
|
+
(state.frameloop === 'always' || state.internal.frames > 0) &&
|
|
765
|
+
!state.gl.xr?.isPresenting) {
|
|
766
|
+
repeat += render(timestamp, root);
|
|
1021
767
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
768
|
+
}
|
|
769
|
+
// Run after-effects
|
|
770
|
+
flushGlobalEffects('after', timestamp);
|
|
771
|
+
// Stop the loop if nothing invalidates it
|
|
772
|
+
if (repeat === 0) {
|
|
773
|
+
// Tail call effects, they are called when rendering stops
|
|
774
|
+
flushGlobalEffects('tail', timestamp);
|
|
775
|
+
// Flag end of operation
|
|
776
|
+
running = false;
|
|
777
|
+
return cancelAnimationFrame(frame);
|
|
1024
778
|
}
|
|
1025
779
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
}], ctorParameters: function () { return []; } });
|
|
1032
|
-
|
|
1033
|
-
class NgtArgs extends NgtCommonDirective {
|
|
1034
|
-
constructor() {
|
|
1035
|
-
super(...arguments);
|
|
1036
|
-
this.injectedArgs = [];
|
|
1037
|
-
}
|
|
1038
|
-
set args(args) {
|
|
1039
|
-
if (args == null || !Array.isArray(args) || (args.length === 1 && args[0] === null))
|
|
780
|
+
function invalidate(store, frames = 1) {
|
|
781
|
+
const state = store?.get();
|
|
782
|
+
if (!state)
|
|
783
|
+
return roots.forEach((root) => invalidate(root, frames));
|
|
784
|
+
if (state.gl.xr?.isPresenting || !state.internal.active || state.frameloop === 'never')
|
|
1040
785
|
return;
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
this.injected = true;
|
|
1048
|
-
return this.injectedArgs;
|
|
786
|
+
// Increase frames, do not go higher than 60
|
|
787
|
+
state.internal.frames = Math.min(60, state.internal.frames + frames);
|
|
788
|
+
// If the render-loop isn't active, start it
|
|
789
|
+
if (!running) {
|
|
790
|
+
running = true;
|
|
791
|
+
requestAnimationFrame(loop);
|
|
1049
792
|
}
|
|
1050
|
-
return null;
|
|
1051
793
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
794
|
+
function advance(timestamp, runGlobalEffects = true, store, frame) {
|
|
795
|
+
const state = store?.get();
|
|
796
|
+
if (runGlobalEffects)
|
|
797
|
+
flushGlobalEffects('before', timestamp);
|
|
798
|
+
if (!state)
|
|
799
|
+
for (const root of roots.values())
|
|
800
|
+
render(timestamp, root);
|
|
801
|
+
else
|
|
802
|
+
render(timestamp, store, frame);
|
|
803
|
+
if (runGlobalEffects)
|
|
804
|
+
flushGlobalEffects('after', timestamp);
|
|
1054
805
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
806
|
+
return {
|
|
807
|
+
loop,
|
|
808
|
+
/**
|
|
809
|
+
* Invalidates the view, requesting a frame to be rendered. Will globally invalidate unless passed a root's state.
|
|
810
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#invalidate
|
|
811
|
+
*/
|
|
812
|
+
invalidate,
|
|
813
|
+
/**
|
|
814
|
+
* Advances the frameloop and runs render effects, useful for when manually rendering via `frameloop="never"`.
|
|
815
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#advance
|
|
816
|
+
*/
|
|
817
|
+
advance,
|
|
818
|
+
};
|
|
1057
819
|
}
|
|
1058
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtArgs, decorators: [{
|
|
1059
|
-
type: Directive,
|
|
1060
|
-
args: [{ selector: '[args]', standalone: true }]
|
|
1061
|
-
}], propDecorators: { args: [{
|
|
1062
|
-
type: Input
|
|
1063
|
-
}] } });
|
|
1064
820
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
return;
|
|
1073
|
-
this.injected = false;
|
|
1074
|
-
this.injectedParent = parent;
|
|
1075
|
-
this.createView();
|
|
821
|
+
function diffProps(instance, props) {
|
|
822
|
+
const propsEntries = Object.entries(props);
|
|
823
|
+
const changes = [];
|
|
824
|
+
for (const [propKey, propValue] of propsEntries) {
|
|
825
|
+
if (is.equ(propValue, instance[propKey]))
|
|
826
|
+
continue;
|
|
827
|
+
changes.push([propKey, propValue]);
|
|
1076
828
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
829
|
+
return changes;
|
|
830
|
+
}
|
|
831
|
+
function applyProps(instance, props) {
|
|
832
|
+
// if props is empty
|
|
833
|
+
if (!Object.keys(props).length)
|
|
834
|
+
return instance;
|
|
835
|
+
// filter equals, events , and reserved props
|
|
836
|
+
const localState = getLocalState(instance);
|
|
837
|
+
const rootState = localState.store?.get();
|
|
838
|
+
const changes = diffProps(instance, props);
|
|
839
|
+
for (let i = 0; i < changes.length; i++) {
|
|
840
|
+
let key = changes[i][0];
|
|
841
|
+
const currentInstance = instance;
|
|
842
|
+
const targetProp = currentInstance[key];
|
|
843
|
+
let value = changes[i][1];
|
|
844
|
+
if (is.colorSpaceExist(currentInstance)) {
|
|
845
|
+
const sRGBEncoding = 3001;
|
|
846
|
+
const SRGBColorSpace = 'srgb';
|
|
847
|
+
const LinearSRGBColorSpace = 'srgb-linear';
|
|
848
|
+
if (key === 'encoding') {
|
|
849
|
+
key = 'colorSpace';
|
|
850
|
+
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
851
|
+
}
|
|
852
|
+
else if (key === 'outputEncoding') {
|
|
853
|
+
key = 'outputColorSpace';
|
|
854
|
+
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
855
|
+
}
|
|
1081
856
|
}
|
|
1082
|
-
|
|
857
|
+
// special treatmen for objects with support for set/copy, and layers
|
|
858
|
+
if (targetProp && targetProp['set'] && (targetProp['copy'] || targetProp instanceof THREE.Layers)) {
|
|
859
|
+
const isColor = targetProp instanceof THREE.Color;
|
|
860
|
+
// if value is an array
|
|
861
|
+
if (Array.isArray(value)) {
|
|
862
|
+
if (targetProp['fromArray'])
|
|
863
|
+
targetProp['fromArray'](value);
|
|
864
|
+
else
|
|
865
|
+
targetProp['set'](...value);
|
|
866
|
+
}
|
|
867
|
+
// test again target.copy
|
|
868
|
+
else if (targetProp['copy'] &&
|
|
869
|
+
value &&
|
|
870
|
+
value.constructor &&
|
|
871
|
+
targetProp.constructor.name === value.constructor.name) {
|
|
872
|
+
targetProp['copy'](value);
|
|
873
|
+
if (!THREE.ColorManagement && !rootState.linear && isColor)
|
|
874
|
+
targetProp['convertSRGBToLinear']();
|
|
875
|
+
}
|
|
876
|
+
// if nothing else fits, just set the single value, ignore undefined
|
|
877
|
+
else if (value !== undefined) {
|
|
878
|
+
const isColor = targetProp instanceof THREE.Color;
|
|
879
|
+
// allow setting array scalars
|
|
880
|
+
if (!isColor && targetProp['setScalar'])
|
|
881
|
+
targetProp['setScalar'](value);
|
|
882
|
+
// layers have no copy function, copy the mask
|
|
883
|
+
else if (targetProp instanceof THREE.Layers && value instanceof THREE.Layers)
|
|
884
|
+
targetProp.mask = value.mask;
|
|
885
|
+
// otherwise just set ...
|
|
886
|
+
else
|
|
887
|
+
targetProp['set'](value);
|
|
888
|
+
// auto-convert srgb
|
|
889
|
+
if (!THREE.ColorManagement && !rootState?.linear && isColor)
|
|
890
|
+
targetProp.convertSRGBToLinear();
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
// else just overwrite the value
|
|
894
|
+
else {
|
|
895
|
+
currentInstance[key] = value;
|
|
896
|
+
// auto-convert srgb textures
|
|
897
|
+
if (currentInstance[key] instanceof THREE.Texture &&
|
|
898
|
+
currentInstance[key].format === THREE.RGBAFormat &&
|
|
899
|
+
currentInstance[key].type === THREE.UnsignedByteType) {
|
|
900
|
+
const texture = currentInstance[key];
|
|
901
|
+
if (is.colorSpaceExist(texture) && is.colorSpaceExist(rootState.gl))
|
|
902
|
+
texture.colorSpace = rootState.gl.outputColorSpace;
|
|
903
|
+
else
|
|
904
|
+
texture.encoding = rootState.gl.outputEncoding;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
checkUpdate(targetProp);
|
|
908
|
+
invalidateInstance(instance);
|
|
909
|
+
}
|
|
910
|
+
const instanceHandlers = localState.eventCount;
|
|
911
|
+
const parent = localState.parent ? untracked(localState.parent) : null;
|
|
912
|
+
if (parent && rootState.internal && instance['raycast'] && instanceHandlers !== localState.eventCount) {
|
|
913
|
+
// Pre-emptively remove the instance from the interaction manager
|
|
914
|
+
const index = rootState.internal.interaction.indexOf(instance);
|
|
915
|
+
if (index > -1)
|
|
916
|
+
rootState.internal.interaction.splice(index, 1);
|
|
917
|
+
// Add the instance to the interaction manager only when it has handlers
|
|
918
|
+
if (localState.eventCount)
|
|
919
|
+
rootState.internal.interaction.push(instance);
|
|
1083
920
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
921
|
+
if (parent && localState.afterUpdate && localState.afterUpdate.observed && changes.length) {
|
|
922
|
+
localState.afterUpdate.emit(instance);
|
|
1086
923
|
}
|
|
1087
|
-
|
|
1088
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtParent, isStandalone: true, selector: "[parent]", inputs: { parent: "parent" }, usesInheritance: true, ngImport: i0 }); }
|
|
924
|
+
return instance;
|
|
1089
925
|
}
|
|
1090
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtParent, decorators: [{
|
|
1091
|
-
type: Directive,
|
|
1092
|
-
args: [{ selector: '[parent]', standalone: true }]
|
|
1093
|
-
}], propDecorators: { parent: [{
|
|
1094
|
-
type: Input
|
|
1095
|
-
}] } });
|
|
1096
926
|
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
927
|
+
const STORE_COMPUTED_KEY = '__ngt_store_computed__';
|
|
928
|
+
class NgtSignalStore {
|
|
929
|
+
#state;
|
|
930
|
+
#computedCache = new Map();
|
|
931
|
+
constructor(initialState = {}) {
|
|
932
|
+
initialState ??= {};
|
|
933
|
+
this.#state = signal(Object.assign(initialState, { __ngt_dummy_state__: Date.now() }));
|
|
934
|
+
}
|
|
935
|
+
select(...keysAndOptions) {
|
|
936
|
+
if (keysAndOptions.length === 0)
|
|
937
|
+
return this.#state.asReadonly();
|
|
938
|
+
if (keysAndOptions.length === 1 && typeof keysAndOptions[0] === 'object') {
|
|
939
|
+
if (!this.#computedCache.has(STORE_COMPUTED_KEY)) {
|
|
940
|
+
this.#computedCache.set(STORE_COMPUTED_KEY, computed(() => this.#state(), keysAndOptions));
|
|
941
|
+
return this.#computedCache.get(STORE_COMPUTED_KEY);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
const [keys, options] = parseOptions(keysAndOptions);
|
|
945
|
+
const joinedKeys = keys.join('-');
|
|
946
|
+
if (!this.#computedCache.has(joinedKeys)) {
|
|
947
|
+
this.#computedCache.set(joinedKeys, computed(() => {
|
|
948
|
+
const state = this.#state();
|
|
949
|
+
return keys.reduce((value, key) => value[key], state);
|
|
950
|
+
}, options));
|
|
951
|
+
}
|
|
952
|
+
return this.#computedCache.get(joinedKeys);
|
|
953
|
+
}
|
|
954
|
+
get(...keys) {
|
|
955
|
+
const state = untracked(this.#state);
|
|
956
|
+
if (keys.length === 0)
|
|
957
|
+
return state;
|
|
958
|
+
return keys.reduce((value, key) => value[key], state);
|
|
959
|
+
}
|
|
960
|
+
set(state) {
|
|
961
|
+
this.#state.update((previous) => ({
|
|
962
|
+
...previous,
|
|
963
|
+
...(typeof state === 'function' ? state(previous) : state),
|
|
964
|
+
}));
|
|
1106
965
|
}
|
|
966
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtSignalStore, deps: [{ token: 'INITIAL_STATE', optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
967
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtSignalStore }); }
|
|
1107
968
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
internal.capturedMap.forEach((captures, pointerId) => {
|
|
1120
|
-
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
1121
|
-
});
|
|
1122
|
-
if (store.get('previousStore')) {
|
|
1123
|
-
removeInteractivity(store.get('previousStore'), object);
|
|
969
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtSignalStore, decorators: [{
|
|
970
|
+
type: Injectable
|
|
971
|
+
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
|
972
|
+
type: Optional
|
|
973
|
+
}, {
|
|
974
|
+
type: Inject,
|
|
975
|
+
args: ['INITIAL_STATE']
|
|
976
|
+
}] }]; } });
|
|
977
|
+
function parseOptions(keysAndOptions) {
|
|
978
|
+
if (typeof keysAndOptions.at(-1) === 'object') {
|
|
979
|
+
return [keysAndOptions.slice(0, -1), keysAndOptions.at(-1)];
|
|
1124
980
|
}
|
|
981
|
+
return [keysAndOptions];
|
|
1125
982
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
const eventName = `pointer${name}`;
|
|
1138
|
-
return getLocalState(obj).handlers?.[eventName];
|
|
1139
|
-
}));
|
|
983
|
+
|
|
984
|
+
const rootStateMap = new Map();
|
|
985
|
+
const { invalidate, advance } = createLoop(rootStateMap);
|
|
986
|
+
const shallowLoose = { objects: 'shallow', strict: false };
|
|
987
|
+
class NgtStore extends NgtSignalStore {
|
|
988
|
+
constructor() {
|
|
989
|
+
super(...arguments);
|
|
990
|
+
this.#parentStore = inject(NgtStore, { optional: true, skipSelf: true });
|
|
991
|
+
this.#window = inject(DOCUMENT).defaultView;
|
|
992
|
+
this.#injector = inject(Injector);
|
|
993
|
+
this.isInit = false;
|
|
1140
994
|
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
const
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
995
|
+
#parentStore;
|
|
996
|
+
#window;
|
|
997
|
+
#injector;
|
|
998
|
+
init() {
|
|
999
|
+
if (!this.isInit) {
|
|
1000
|
+
const position = new THREE.Vector3();
|
|
1001
|
+
const defaultTarget = new THREE.Vector3();
|
|
1002
|
+
const tempTarget = new THREE.Vector3();
|
|
1003
|
+
const getCurrentViewport = (camera = this.get('camera'), target = defaultTarget, size = this.get('size')) => {
|
|
1004
|
+
const { width, height, top, left } = size;
|
|
1005
|
+
const aspect = width / height;
|
|
1006
|
+
if (target instanceof THREE.Vector3)
|
|
1007
|
+
tempTarget.copy(target);
|
|
1008
|
+
else
|
|
1009
|
+
tempTarget.set(...target);
|
|
1010
|
+
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
1011
|
+
if (is.orthographicCamera(camera)) {
|
|
1012
|
+
return {
|
|
1013
|
+
width: width / camera.zoom,
|
|
1014
|
+
height: height / camera.zoom,
|
|
1015
|
+
top,
|
|
1016
|
+
left,
|
|
1017
|
+
factor: 1,
|
|
1018
|
+
distance,
|
|
1019
|
+
aspect,
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
const fov = (camera.fov * Math.PI) / 180; // convert vertical fov to radians
|
|
1023
|
+
const h = 2 * Math.tan(fov / 2) * distance; // visible height
|
|
1024
|
+
const w = h * aspect;
|
|
1025
|
+
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
1026
|
+
};
|
|
1027
|
+
let performanceTimeout;
|
|
1028
|
+
const setPerformanceCurrent = (current) => {
|
|
1029
|
+
this.set((state) => ({ performance: { ...state.performance, current } }));
|
|
1030
|
+
};
|
|
1031
|
+
this.set({
|
|
1032
|
+
get: this.get.bind(this),
|
|
1033
|
+
set: this.set.bind(this),
|
|
1034
|
+
ready: false,
|
|
1035
|
+
events: { priority: 1, enabled: true, connected: false },
|
|
1036
|
+
invalidate: (frames = 1) => invalidate(this, frames),
|
|
1037
|
+
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, this),
|
|
1038
|
+
legacy: false,
|
|
1039
|
+
linear: false,
|
|
1040
|
+
flat: false,
|
|
1041
|
+
controls: null,
|
|
1042
|
+
clock: new THREE.Clock(),
|
|
1043
|
+
pointer: new THREE.Vector2(),
|
|
1044
|
+
frameloop: 'always',
|
|
1045
|
+
performance: {
|
|
1046
|
+
current: 1,
|
|
1047
|
+
min: 0.5,
|
|
1048
|
+
max: 1,
|
|
1049
|
+
debounce: 200,
|
|
1050
|
+
regress: () => {
|
|
1051
|
+
const state = this.get();
|
|
1052
|
+
// clear timeout
|
|
1053
|
+
if (performanceTimeout)
|
|
1054
|
+
clearTimeout(performanceTimeout);
|
|
1055
|
+
// set lower bound
|
|
1056
|
+
if (state.performance.current !== state.performance.min)
|
|
1057
|
+
setPerformanceCurrent(state.performance.min);
|
|
1058
|
+
// go back to upper bound
|
|
1059
|
+
performanceTimeout = setTimeout(() => setPerformanceCurrent(this.get('performance', 'max') || 1), state.performance.debounce);
|
|
1060
|
+
},
|
|
1061
|
+
},
|
|
1062
|
+
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
1063
|
+
viewport: {
|
|
1064
|
+
initialDpr: 0,
|
|
1065
|
+
dpr: 0,
|
|
1066
|
+
width: 0,
|
|
1067
|
+
height: 0,
|
|
1068
|
+
top: 0,
|
|
1069
|
+
left: 0,
|
|
1070
|
+
aspect: 0,
|
|
1071
|
+
distance: 0,
|
|
1072
|
+
factor: 0,
|
|
1073
|
+
getCurrentViewport,
|
|
1074
|
+
},
|
|
1075
|
+
previousStore: this.#parentStore,
|
|
1076
|
+
internal: {
|
|
1077
|
+
active: false,
|
|
1078
|
+
priority: 0,
|
|
1079
|
+
frames: 0,
|
|
1080
|
+
lastEvent: new ElementRef(null),
|
|
1081
|
+
interaction: [],
|
|
1082
|
+
hovered: new Map(),
|
|
1083
|
+
subscribers: [],
|
|
1084
|
+
initialClick: [0, 0],
|
|
1085
|
+
initialHits: [],
|
|
1086
|
+
capturedMap: new Map(),
|
|
1087
|
+
subscribe: (callback, priority = 0, store = this) => {
|
|
1088
|
+
const internal = this.get('internal');
|
|
1089
|
+
// If this subscription was given a priority, it takes rendering into its own hands
|
|
1090
|
+
// For that reason we switch off automatic rendering and increase the manual flag
|
|
1091
|
+
// As long as this flag is positive there can be no internal rendering at all
|
|
1092
|
+
// because there could be multiple render subscriptions
|
|
1093
|
+
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1094
|
+
internal.subscribers.push({ priority, store, callback });
|
|
1095
|
+
// Register subscriber and sort layers from lowest to highest, meaning,
|
|
1096
|
+
// highest priority renders last (on top of the other frames)
|
|
1097
|
+
internal.subscribers.sort((a, b) => (a.priority || 0) - (b.priority || 0));
|
|
1098
|
+
return () => {
|
|
1099
|
+
const internal = this.get('internal');
|
|
1100
|
+
if (internal?.subscribers) {
|
|
1101
|
+
// Decrease manual flag if this subscription had a priority
|
|
1102
|
+
internal.priority = internal.priority - (priority > 0 ? 1 : 0);
|
|
1103
|
+
// Remove subscriber from list
|
|
1104
|
+
internal.subscribers = internal.subscribers.filter((s) => s.callback !== callback);
|
|
1105
|
+
}
|
|
1106
|
+
};
|
|
1107
|
+
},
|
|
1108
|
+
},
|
|
1109
|
+
setEvents: (events) => {
|
|
1110
|
+
this.set((state) => ({ events: { ...state.events, ...events } }));
|
|
1111
|
+
},
|
|
1112
|
+
setSize: (width, height, top, left) => {
|
|
1113
|
+
const camera = this.get('camera');
|
|
1114
|
+
const size = { width, height, top: top || 0, left: left || 0 };
|
|
1115
|
+
this.set((state) => ({
|
|
1116
|
+
size,
|
|
1117
|
+
viewport: { ...state.viewport, ...getCurrentViewport(camera, defaultTarget, size) },
|
|
1118
|
+
}));
|
|
1119
|
+
},
|
|
1120
|
+
setDpr: (dpr) => {
|
|
1121
|
+
const resolved = makeDpr(dpr, this.#window);
|
|
1122
|
+
this.set((state) => ({
|
|
1123
|
+
viewport: {
|
|
1124
|
+
...state.viewport,
|
|
1125
|
+
dpr: resolved,
|
|
1126
|
+
initialDpr: state.viewport.initialDpr || resolved,
|
|
1127
|
+
},
|
|
1128
|
+
}));
|
|
1129
|
+
},
|
|
1130
|
+
setFrameloop: (frameloop = 'always') => {
|
|
1131
|
+
const clock = this.get('clock');
|
|
1132
|
+
clock.stop();
|
|
1133
|
+
clock.elapsedTime = 0;
|
|
1134
|
+
if (frameloop !== 'never') {
|
|
1135
|
+
clock.start();
|
|
1136
|
+
clock.elapsedTime = 0;
|
|
1137
|
+
}
|
|
1138
|
+
this.set({ frameloop });
|
|
1139
|
+
},
|
|
1140
|
+
});
|
|
1141
|
+
this.isInit = true;
|
|
1142
|
+
this.#resize();
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
configure(inputs, canvasElement) {
|
|
1146
|
+
const { gl: glOptions, size: sizeOptions, camera: cameraOptions, raycaster: raycasterOptions, scene: sceneOptions, events, orthographic, lookAt, shadows, linear, legacy, flat, dpr, frameloop, performance, } = inputs;
|
|
1147
|
+
const state = this.get();
|
|
1148
|
+
const stateToUpdate = {};
|
|
1149
|
+
// setup renderer
|
|
1150
|
+
let gl = state.gl;
|
|
1151
|
+
if (!state.gl)
|
|
1152
|
+
stateToUpdate.gl = gl = makeDefaultRenderer(glOptions, canvasElement);
|
|
1153
|
+
// setup raycaster
|
|
1154
|
+
let raycaster = state.raycaster;
|
|
1155
|
+
if (!raycaster)
|
|
1156
|
+
stateToUpdate.raycaster = raycaster = new THREE.Raycaster();
|
|
1157
|
+
// set raycaster options
|
|
1158
|
+
const { params, ...options } = raycasterOptions || {};
|
|
1159
|
+
if (!is.equ(options, raycaster, shallowLoose))
|
|
1160
|
+
applyProps(raycaster, { ...options });
|
|
1161
|
+
if (!is.equ(params, raycaster.params, shallowLoose)) {
|
|
1162
|
+
applyProps(raycaster, { params: { ...raycaster.params, ...(params || {}) } });
|
|
1163
|
+
}
|
|
1164
|
+
// create default camera
|
|
1165
|
+
if (!state.camera) {
|
|
1166
|
+
const isCamera = is.camera(cameraOptions);
|
|
1167
|
+
let camera = isCamera ? cameraOptions : makeDefaultCamera(orthographic || false, state.size);
|
|
1168
|
+
if (!isCamera) {
|
|
1169
|
+
if (cameraOptions)
|
|
1170
|
+
applyProps(camera, cameraOptions);
|
|
1171
|
+
// set position.z
|
|
1172
|
+
if (!cameraOptions?.position)
|
|
1173
|
+
camera.position.z = 5;
|
|
1174
|
+
// always look at center or passed-in lookAt by default
|
|
1175
|
+
if (!cameraOptions?.rotation && !cameraOptions?.quaternion) {
|
|
1176
|
+
if (Array.isArray(lookAt))
|
|
1177
|
+
camera.lookAt(lookAt[0], lookAt[1], lookAt[2]);
|
|
1178
|
+
else if (lookAt instanceof THREE.Vector3)
|
|
1179
|
+
camera.lookAt(lookAt);
|
|
1180
|
+
else
|
|
1181
|
+
camera.lookAt(0, 0, 0);
|
|
1205
1182
|
}
|
|
1206
|
-
|
|
1183
|
+
// update projection matrix after applyprops
|
|
1184
|
+
camera.updateProjectionMatrix?.();
|
|
1207
1185
|
}
|
|
1186
|
+
if (!is.instance(camera))
|
|
1187
|
+
camera = prepare(camera, { store: this });
|
|
1188
|
+
stateToUpdate.camera = camera;
|
|
1208
1189
|
}
|
|
1209
|
-
//
|
|
1210
|
-
if (
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1190
|
+
// Set up scene (one time only!)
|
|
1191
|
+
if (!state.scene) {
|
|
1192
|
+
let scene;
|
|
1193
|
+
if (sceneOptions instanceof THREE.Scene) {
|
|
1194
|
+
scene = prepare(sceneOptions, { store: this });
|
|
1195
|
+
}
|
|
1196
|
+
else {
|
|
1197
|
+
scene = prepare(new THREE.Scene(), { store: this });
|
|
1198
|
+
if (sceneOptions)
|
|
1199
|
+
applyProps(scene, sceneOptions);
|
|
1215
1200
|
}
|
|
1201
|
+
stateToUpdate.scene = scene;
|
|
1216
1202
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
const
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
const
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
stopped: localState.stopped,
|
|
1265
|
-
delta,
|
|
1266
|
-
unprojectedPoint,
|
|
1267
|
-
ray: raycaster.ray,
|
|
1268
|
-
camera: camera,
|
|
1269
|
-
// Hijack stopPropagation, which just sets a flag
|
|
1270
|
-
stopPropagation() {
|
|
1271
|
-
// https://github.com/pmndrs/react-three-fiber/issues/596
|
|
1272
|
-
// Events are not allowed to stop propagation if the pointer has been captured
|
|
1273
|
-
const capturesForPointer = 'pointerId' in event && internal.capturedMap.get(event.pointerId);
|
|
1274
|
-
// We only authorize stopPropagation...
|
|
1275
|
-
if (
|
|
1276
|
-
// ...if this pointer hasn't been captured
|
|
1277
|
-
!capturesForPointer ||
|
|
1278
|
-
// ... or if the hit object is capturing the pointer
|
|
1279
|
-
capturesForPointer.has(hit.eventObject)) {
|
|
1280
|
-
raycastEvent.stopped = localState.stopped = true;
|
|
1281
|
-
// Propagation is stopped, remove all other hover records
|
|
1282
|
-
// An event handler is only allowed to flush other handlers if it is hovered itself
|
|
1283
|
-
if (internal.hovered.size &&
|
|
1284
|
-
Array.from(internal.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
1285
|
-
// Objects cannot flush out higher up objects that have already caught the event
|
|
1286
|
-
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
1287
|
-
cancelPointer([...higher, hit]);
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
},
|
|
1291
|
-
// there should be a distinction between target and currentTarget
|
|
1292
|
-
target: { hasPointerCapture, setPointerCapture, releasePointerCapture },
|
|
1293
|
-
currentTarget: { hasPointerCapture, setPointerCapture, releasePointerCapture },
|
|
1294
|
-
nativeEvent: event,
|
|
1203
|
+
// Set up XR (one time only!)
|
|
1204
|
+
if (!state.xr) {
|
|
1205
|
+
// Handle frame behavior in WebXR
|
|
1206
|
+
const handleXRFrame = (timestamp, frame) => {
|
|
1207
|
+
const state = this.get();
|
|
1208
|
+
if (state.frameloop === 'never')
|
|
1209
|
+
return;
|
|
1210
|
+
advance(timestamp, true, this, frame);
|
|
1211
|
+
};
|
|
1212
|
+
// Toggle render switching on session
|
|
1213
|
+
const handleSessionChange = () => {
|
|
1214
|
+
const state = this.get();
|
|
1215
|
+
state.gl.xr.enabled = state.gl.xr.isPresenting;
|
|
1216
|
+
state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
|
|
1217
|
+
if (!state.gl.xr.isPresenting)
|
|
1218
|
+
state.invalidate();
|
|
1219
|
+
};
|
|
1220
|
+
// WebXR session manager
|
|
1221
|
+
const xr = {
|
|
1222
|
+
connect: () => {
|
|
1223
|
+
gl.xr.addEventListener('sessionstart', handleSessionChange);
|
|
1224
|
+
gl.xr.addEventListener('sessionend', handleSessionChange);
|
|
1225
|
+
},
|
|
1226
|
+
disconnect: () => {
|
|
1227
|
+
gl.xr.removeEventListener('sessionstart', handleSessionChange);
|
|
1228
|
+
gl.xr.removeEventListener('sessionend', handleSessionChange);
|
|
1229
|
+
},
|
|
1230
|
+
};
|
|
1231
|
+
// Subscribe to WebXR session events
|
|
1232
|
+
if (gl.xr)
|
|
1233
|
+
xr.connect();
|
|
1234
|
+
stateToUpdate.xr = xr;
|
|
1235
|
+
}
|
|
1236
|
+
// Set shadowmap
|
|
1237
|
+
if (gl.shadowMap) {
|
|
1238
|
+
const oldEnabled = gl.shadowMap.enabled;
|
|
1239
|
+
const oldType = gl.shadowMap.type;
|
|
1240
|
+
gl.shadowMap.enabled = !!shadows;
|
|
1241
|
+
if (typeof shadows === 'boolean') {
|
|
1242
|
+
gl.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
1243
|
+
}
|
|
1244
|
+
else if (typeof shadows === 'string') {
|
|
1245
|
+
const types = {
|
|
1246
|
+
basic: THREE.BasicShadowMap,
|
|
1247
|
+
percentage: THREE.PCFShadowMap,
|
|
1248
|
+
soft: THREE.PCFSoftShadowMap,
|
|
1249
|
+
variance: THREE.VSMShadowMap,
|
|
1295
1250
|
};
|
|
1296
|
-
|
|
1297
|
-
callback(raycastEvent);
|
|
1298
|
-
// event bubbling may be interupted by stopPropagation
|
|
1299
|
-
if (localState.stopped === true)
|
|
1300
|
-
break;
|
|
1251
|
+
gl.shadowMap.type = types[shadows] ?? THREE.PCFSoftShadowMap;
|
|
1301
1252
|
}
|
|
1253
|
+
else if (is.obj(shadows)) {
|
|
1254
|
+
Object.assign(gl.shadowMap, shadows);
|
|
1255
|
+
}
|
|
1256
|
+
if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type)
|
|
1257
|
+
checkNeedsUpdate(gl.shadowMap);
|
|
1302
1258
|
}
|
|
1303
|
-
|
|
1259
|
+
// Safely set color management if available.
|
|
1260
|
+
// Avoid accessing THREE.ColorManagement to play nice with older versions
|
|
1261
|
+
if (THREE.ColorManagement) {
|
|
1262
|
+
const ColorManagement = THREE.ColorManagement;
|
|
1263
|
+
if ('enabled' in ColorManagement)
|
|
1264
|
+
ColorManagement['enabled'] = !legacy ?? false;
|
|
1265
|
+
else if ('legacyMode' in ColorManagement)
|
|
1266
|
+
ColorManagement['legacyMode'] = legacy ?? true;
|
|
1267
|
+
}
|
|
1268
|
+
// set color space and tonemapping preferences
|
|
1269
|
+
const LinearEncoding = 3000;
|
|
1270
|
+
const sRGBEncoding = 3001;
|
|
1271
|
+
applyProps(gl, {
|
|
1272
|
+
outputEncoding: linear ? LinearEncoding : sRGBEncoding,
|
|
1273
|
+
toneMapping: flat ? THREE.NoToneMapping : THREE.ACESFilmicToneMapping,
|
|
1274
|
+
});
|
|
1275
|
+
// Update color management state
|
|
1276
|
+
if (state.legacy !== legacy)
|
|
1277
|
+
stateToUpdate.legacy = legacy;
|
|
1278
|
+
if (state.linear !== linear)
|
|
1279
|
+
stateToUpdate.linear = linear;
|
|
1280
|
+
if (state.flat !== flat)
|
|
1281
|
+
stateToUpdate.flat = flat;
|
|
1282
|
+
// Set gl props
|
|
1283
|
+
gl.setClearAlpha(0);
|
|
1284
|
+
gl.setPixelRatio(makeDpr(state.viewport.dpr));
|
|
1285
|
+
gl.setSize(state.size.width, state.size.height);
|
|
1286
|
+
if (is.obj(glOptions) &&
|
|
1287
|
+
!(typeof glOptions === 'function') &&
|
|
1288
|
+
!is.renderer(glOptions) &&
|
|
1289
|
+
!is.equ(glOptions, gl, shallowLoose)) {
|
|
1290
|
+
applyProps(gl, glOptions);
|
|
1291
|
+
}
|
|
1292
|
+
// Store events internally
|
|
1293
|
+
if (events && !state.events.handlers)
|
|
1294
|
+
stateToUpdate.events = events(this);
|
|
1295
|
+
// Check performance
|
|
1296
|
+
if (performance && !is.equ(performance, state.performance, shallowLoose)) {
|
|
1297
|
+
stateToUpdate.performance = { ...state.performance, ...performance };
|
|
1298
|
+
}
|
|
1299
|
+
this.set(stateToUpdate);
|
|
1300
|
+
// Check pixelratio
|
|
1301
|
+
if (dpr && state.viewport.dpr !== makeDpr(dpr))
|
|
1302
|
+
state.setDpr(dpr);
|
|
1303
|
+
// Check size, allow it to take on container bounds initially
|
|
1304
|
+
const size = computeInitialSize(canvasElement, sizeOptions);
|
|
1305
|
+
if (!is.equ(size, state.size, shallowLoose))
|
|
1306
|
+
state.setSize(size.width, size.height, size.top, size.left);
|
|
1307
|
+
// Check frameloop
|
|
1308
|
+
if (state.frameloop !== frameloop)
|
|
1309
|
+
state.setFrameloop(frameloop);
|
|
1310
|
+
if (!this.get('ready'))
|
|
1311
|
+
this.set({ ready: true });
|
|
1312
|
+
this.#invalidate();
|
|
1304
1313
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
hit.index === hoveredObj.index &&
|
|
1313
|
-
hit.instanceId === hoveredObj.instanceId)) {
|
|
1314
|
-
const eventObject = hoveredObj.eventObject;
|
|
1315
|
-
const instance = getLocalState(eventObject);
|
|
1316
|
-
const handlers = instance?.handlers;
|
|
1317
|
-
internal.hovered.delete(makeId(hoveredObj));
|
|
1318
|
-
if (instance?.eventCount) {
|
|
1319
|
-
// Clear out intersects, they are outdated by now
|
|
1320
|
-
const data = { ...hoveredObj, intersections };
|
|
1321
|
-
handlers?.pointerout?.(data);
|
|
1322
|
-
handlers?.pointerleave?.(data);
|
|
1314
|
+
destroy(canvas) {
|
|
1315
|
+
this.set((state) => ({ internal: { ...state.internal, active: false } }));
|
|
1316
|
+
setTimeout(() => {
|
|
1317
|
+
const { gl, xr, events } = this.get();
|
|
1318
|
+
if (gl) {
|
|
1319
|
+
if (events.disconnect) {
|
|
1320
|
+
events.disconnect();
|
|
1323
1321
|
}
|
|
1322
|
+
gl.renderLists.dispose();
|
|
1323
|
+
gl.forceContextLoss();
|
|
1324
|
+
if (gl.xr && gl.xr.enabled) {
|
|
1325
|
+
gl.xr.setAnimationLoop(null);
|
|
1326
|
+
xr.disconnect();
|
|
1327
|
+
}
|
|
1328
|
+
dispose(this.get());
|
|
1329
|
+
rootStateMap.delete(canvas);
|
|
1324
1330
|
}
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
function pointerMissed(event, objects) {
|
|
1328
|
-
for (let i = 0; i < objects.length; i++) {
|
|
1329
|
-
const instance = getLocalState(objects[i]);
|
|
1330
|
-
instance?.handlers.pointermissed?.(event);
|
|
1331
|
-
}
|
|
1331
|
+
}, 500);
|
|
1332
1332
|
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
const isPointerMove = name === 'pointermove';
|
|
1357
|
-
const isClickEvent = name === 'click' || name === 'contextmenu' || name === 'dblclick';
|
|
1358
|
-
const filter = isPointerMove ? filterPointerEvents : undefined;
|
|
1359
|
-
// const hits = patchIntersects(intersect(filter), event)
|
|
1360
|
-
const hits = intersect(event, filter);
|
|
1361
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
1362
|
-
// Save initial coordinates on pointer-down
|
|
1363
|
-
if (name === 'pointerdown') {
|
|
1364
|
-
internal.initialClick = [event.offsetX, event.offsetY];
|
|
1365
|
-
internal.initialHits = hits.map((hit) => hit.eventObject);
|
|
1366
|
-
}
|
|
1367
|
-
// If a click yields no results, pass it back to the user as a miss
|
|
1368
|
-
// Missed events have to come first in order to establish user-land side-effect clean up
|
|
1369
|
-
if (isClickEvent && !hits.length) {
|
|
1370
|
-
if (delta <= 2) {
|
|
1371
|
-
pointerMissed(event, internal.interaction);
|
|
1372
|
-
if (onPointerMissed)
|
|
1373
|
-
onPointerMissed(event);
|
|
1374
|
-
}
|
|
1333
|
+
#resize() {
|
|
1334
|
+
const state = this.get();
|
|
1335
|
+
let oldSize = state.size;
|
|
1336
|
+
let oldDpr = state.viewport.dpr;
|
|
1337
|
+
let oldCamera = state.camera;
|
|
1338
|
+
const triggers = computed(() => {
|
|
1339
|
+
return {
|
|
1340
|
+
camera: this.select('camera')(),
|
|
1341
|
+
size: this.select('size')(),
|
|
1342
|
+
viewport: this.select('viewport')(),
|
|
1343
|
+
gl: this.get('gl'),
|
|
1344
|
+
};
|
|
1345
|
+
});
|
|
1346
|
+
effect(() => {
|
|
1347
|
+
const { camera, size, viewport, gl } = triggers();
|
|
1348
|
+
// resize camera and renderer on changes to size and dpr
|
|
1349
|
+
if (size !== oldSize || viewport.dpr !== oldDpr) {
|
|
1350
|
+
oldSize = size;
|
|
1351
|
+
oldDpr = viewport.dpr;
|
|
1352
|
+
// update camera
|
|
1353
|
+
updateCamera(camera, size);
|
|
1354
|
+
gl.setPixelRatio(viewport.dpr);
|
|
1355
|
+
gl.setSize(size.width, size.height);
|
|
1375
1356
|
}
|
|
1376
|
-
//
|
|
1377
|
-
if (
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
// Check presence of handlers
|
|
1384
|
-
if (!instance?.eventCount)
|
|
1385
|
-
return;
|
|
1386
|
-
if (isPointerMove) {
|
|
1387
|
-
// Move event ...
|
|
1388
|
-
if (handlers?.pointerover ||
|
|
1389
|
-
handlers?.pointerenter ||
|
|
1390
|
-
handlers?.pointerout ||
|
|
1391
|
-
handlers?.pointerleave) {
|
|
1392
|
-
// When enter or out is present take care of hover-state
|
|
1393
|
-
const id = makeId(data);
|
|
1394
|
-
const hoveredItem = internal.hovered.get(id);
|
|
1395
|
-
if (!hoveredItem) {
|
|
1396
|
-
// If the object wasn't previously hovered, book it and call its handler
|
|
1397
|
-
internal.hovered.set(id, data);
|
|
1398
|
-
handlers.pointerover?.(data);
|
|
1399
|
-
handlers.pointerenter?.(data);
|
|
1400
|
-
}
|
|
1401
|
-
else if (hoveredItem.stopped) {
|
|
1402
|
-
// If the object was previously hovered and stopped, we shouldn't allow other items to proceed
|
|
1403
|
-
data.stopPropagation();
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
// Call mouse move
|
|
1407
|
-
handlers?.pointermove?.(data);
|
|
1408
|
-
}
|
|
1409
|
-
else {
|
|
1410
|
-
// All other events ...
|
|
1411
|
-
const handler = handlers?.[name];
|
|
1412
|
-
if (handler) {
|
|
1413
|
-
// Forward all events back to their respective handlers with the exception of click events,
|
|
1414
|
-
// which must use the initial target
|
|
1415
|
-
if (!isClickEvent || internal.initialHits.includes(eventObject)) {
|
|
1416
|
-
// Missed events have to come first
|
|
1417
|
-
pointerMissed(event, internal.interaction.filter((object) => !internal.initialHits.includes(object)));
|
|
1418
|
-
// Now call the handler
|
|
1419
|
-
handler(data);
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
else {
|
|
1423
|
-
// Trigger onPointerMissed on all elements that have pointer over/out handlers, but not click and weren't hit
|
|
1424
|
-
if (isClickEvent && internal.initialHits.includes(eventObject)) {
|
|
1425
|
-
pointerMissed(event, internal.interaction.filter((object) => !internal.initialHits.includes(object)));
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1428
|
-
}
|
|
1357
|
+
// update viewport when camera changes
|
|
1358
|
+
if (camera !== oldCamera) {
|
|
1359
|
+
oldCamera = camera;
|
|
1360
|
+
updateCamera(camera, size);
|
|
1361
|
+
this.set((state) => ({
|
|
1362
|
+
viewport: { ...state.viewport, ...state.viewport.getCurrentViewport(camera) },
|
|
1363
|
+
}));
|
|
1429
1364
|
}
|
|
1430
|
-
|
|
1431
|
-
};
|
|
1365
|
+
}, { injector: this.#injector, allowSignalWrites: true });
|
|
1432
1366
|
}
|
|
1433
|
-
|
|
1367
|
+
#invalidate() {
|
|
1368
|
+
const state = this.select();
|
|
1369
|
+
effect(() => {
|
|
1370
|
+
state().invalidate();
|
|
1371
|
+
}, { injector: this.#injector });
|
|
1372
|
+
}
|
|
1373
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtStore, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1374
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtStore }); }
|
|
1375
|
+
}
|
|
1376
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtStore, decorators: [{
|
|
1377
|
+
type: Injectable
|
|
1378
|
+
}] });
|
|
1379
|
+
function computeInitialSize(canvas, defaultSize) {
|
|
1380
|
+
if (defaultSize)
|
|
1381
|
+
return defaultSize;
|
|
1382
|
+
if (canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
1383
|
+
return canvas.parentElement.getBoundingClientRect();
|
|
1384
|
+
}
|
|
1385
|
+
return { width: 0, height: 0, top: 0, left: 0 };
|
|
1386
|
+
}
|
|
1387
|
+
// Disposes an object and all its properties
|
|
1388
|
+
function dispose(obj) {
|
|
1389
|
+
if (obj.dispose && !is.scene(obj))
|
|
1390
|
+
obj.dispose();
|
|
1391
|
+
for (const p in obj) {
|
|
1392
|
+
p.dispose?.();
|
|
1393
|
+
delete obj[p];
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
const NGT_COMPOUND_PREFIXES = new InjectionToken('NgtCompoundPrefixes');
|
|
1398
|
+
|
|
1399
|
+
const catalogue = {};
|
|
1400
|
+
function extend(objects) {
|
|
1401
|
+
Object.assign(catalogue, objects);
|
|
1434
1402
|
}
|
|
1403
|
+
const NGT_CATALOGUE = new InjectionToken('THREE Constructors Catalogue', { factory: () => catalogue });
|
|
1435
1404
|
|
|
1436
1405
|
function attach(object, value, paths = []) {
|
|
1437
1406
|
const [base, ...remaining] = paths;
|
|
@@ -1463,6 +1432,8 @@ function createAttachFunction(cb) {
|
|
|
1463
1432
|
return (parent, child, store) => cb({ parent, child, store });
|
|
1464
1433
|
}
|
|
1465
1434
|
|
|
1435
|
+
const ROUTED_SCENE = '__ngt_renderer_is_routed_scene__';
|
|
1436
|
+
const SPECIAL_INTERNAL_ADD_COMMENT = '__ngt_renderer_add_comment__';
|
|
1466
1437
|
const SPECIAL_DOM_TAG = {
|
|
1467
1438
|
NGT_PORTAL: 'ngt-portal',
|
|
1468
1439
|
NGT_PRIMITIVE: 'ngt-primitive',
|
|
@@ -1516,7 +1487,7 @@ function attachThreeChild(parent, child) {
|
|
|
1516
1487
|
}
|
|
1517
1488
|
// attach
|
|
1518
1489
|
if (cLS.isRaw) {
|
|
1519
|
-
cLS.parent
|
|
1490
|
+
cLS.parent.set(parent);
|
|
1520
1491
|
// at this point we don't have rawValue yet, so we bail and wait until the Renderer recalls attach
|
|
1521
1492
|
if (child.__ngt_renderer__[11 /* NgtRendererClassId.rawValue */] === undefined)
|
|
1522
1493
|
return;
|
|
@@ -1534,7 +1505,7 @@ function attachThreeChild(parent, child) {
|
|
|
1534
1505
|
added = true;
|
|
1535
1506
|
}
|
|
1536
1507
|
pLS.add(child, added ? 'objects' : 'nonObjects');
|
|
1537
|
-
cLS.parent
|
|
1508
|
+
cLS.parent.set(parent);
|
|
1538
1509
|
if (cLS.afterAttach)
|
|
1539
1510
|
cLS.afterAttach.emit({ parent, node: child });
|
|
1540
1511
|
invalidateInstance(child);
|
|
@@ -1544,11 +1515,11 @@ function removeThreeChild(parent, child, dispose) {
|
|
|
1544
1515
|
const pLS = getLocalState(parent);
|
|
1545
1516
|
const cLS = getLocalState(child);
|
|
1546
1517
|
// clear parent ref
|
|
1547
|
-
cLS.parent
|
|
1518
|
+
cLS.parent?.set(null);
|
|
1548
1519
|
// remove child from parent
|
|
1549
|
-
if (pLS.objects)
|
|
1520
|
+
if (untracked(pLS.objects))
|
|
1550
1521
|
pLS.remove(child, 'objects');
|
|
1551
|
-
if (pLS.nonObjects)
|
|
1522
|
+
if (untracked(pLS.nonObjects))
|
|
1552
1523
|
pLS.remove(child, 'nonObjects');
|
|
1553
1524
|
if (cLS.attach) {
|
|
1554
1525
|
detach(parent, child, cLS.attach);
|
|
@@ -1559,8 +1530,8 @@ function removeThreeChild(parent, child, dispose) {
|
|
|
1559
1530
|
}
|
|
1560
1531
|
const isPrimitive = cLS.primitive;
|
|
1561
1532
|
if (!isPrimitive) {
|
|
1562
|
-
removeThreeRecursive(cLS.objects
|
|
1563
|
-
removeThreeRecursive(child.
|
|
1533
|
+
removeThreeRecursive(cLS.objects ? untracked(cLS.objects) : [], child, !!dispose);
|
|
1534
|
+
removeThreeRecursive(child.children, child, !!dispose);
|
|
1564
1535
|
}
|
|
1565
1536
|
// dispose
|
|
1566
1537
|
if (!isPrimitive && child['dispose'] && !is.scene(child)) {
|
|
@@ -1572,64 +1543,164 @@ function removeThreeRecursive(array, parent, dispose) {
|
|
|
1572
1543
|
if (array)
|
|
1573
1544
|
[...array].forEach((child) => removeThreeChild(parent, child, dispose));
|
|
1574
1545
|
}
|
|
1575
|
-
function processThreeEvent(instance, priority, eventName, callback,
|
|
1546
|
+
function processThreeEvent(instance, priority, eventName, callback, zone, cdr) {
|
|
1576
1547
|
const lS = getLocalState(instance);
|
|
1577
1548
|
if (eventName === SPECIAL_EVENTS.BEFORE_RENDER) {
|
|
1578
1549
|
return lS.store
|
|
1579
1550
|
.get('internal')
|
|
1580
1551
|
.subscribe((state) => callback({ state, object: instance }), priority || lS.priority || 0);
|
|
1581
1552
|
}
|
|
1582
|
-
if (eventName === SPECIAL_EVENTS.AFTER_UPDATE || eventName === SPECIAL_EVENTS.AFTER_ATTACH) {
|
|
1583
|
-
let emitter = lS[eventName];
|
|
1584
|
-
if (!emitter)
|
|
1585
|
-
emitter = lS[eventName] = new EventEmitter();
|
|
1586
|
-
const sub = emitter.subscribe(callback);
|
|
1587
|
-
return sub.unsubscribe.bind(sub);
|
|
1553
|
+
if (eventName === SPECIAL_EVENTS.AFTER_UPDATE || eventName === SPECIAL_EVENTS.AFTER_ATTACH) {
|
|
1554
|
+
let emitter = lS[eventName];
|
|
1555
|
+
if (!emitter)
|
|
1556
|
+
emitter = lS[eventName] = new EventEmitter();
|
|
1557
|
+
const sub = emitter.subscribe(callback);
|
|
1558
|
+
return sub.unsubscribe.bind(sub);
|
|
1559
|
+
}
|
|
1560
|
+
if (!lS.handlers)
|
|
1561
|
+
lS.handlers = {};
|
|
1562
|
+
// try to get the previous handler. compound might have one, the THREE object might also have one with the same name
|
|
1563
|
+
const previousHandler = lS.handlers[eventName];
|
|
1564
|
+
// readjust the callback
|
|
1565
|
+
const updatedCallback = (event) => {
|
|
1566
|
+
if (previousHandler)
|
|
1567
|
+
previousHandler(event);
|
|
1568
|
+
zone.run(() => {
|
|
1569
|
+
callback(event);
|
|
1570
|
+
safeDetectChanges(cdr);
|
|
1571
|
+
// cdr.detectChanges();
|
|
1572
|
+
});
|
|
1573
|
+
};
|
|
1574
|
+
Object.assign(lS.handlers, { [eventName]: eventToHandler(updatedCallback) });
|
|
1575
|
+
// increment the count everytime
|
|
1576
|
+
lS.eventCount += 1;
|
|
1577
|
+
// but only add the instance (target) to the interaction array (so that it is handled by the EventManager with Raycast)
|
|
1578
|
+
// the first time eventCount is incremented
|
|
1579
|
+
if (lS.eventCount === 1 && instance['raycast'])
|
|
1580
|
+
lS.store.get('internal', 'interaction').push(instance);
|
|
1581
|
+
// clean up the event listener by removing the target from the interaction array
|
|
1582
|
+
return () => {
|
|
1583
|
+
const localState = getLocalState(instance);
|
|
1584
|
+
if (localState && localState.eventCount) {
|
|
1585
|
+
const index = localState.store
|
|
1586
|
+
.get('internal', 'interaction')
|
|
1587
|
+
.findIndex((obj) => obj.uuid === instance.uuid);
|
|
1588
|
+
if (index >= 0)
|
|
1589
|
+
localState.store.get('internal', 'interaction').splice(index, 1);
|
|
1590
|
+
}
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
function eventToHandler(callback) {
|
|
1594
|
+
return (event) => {
|
|
1595
|
+
callback(event);
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1598
|
+
function kebabToPascal(str) {
|
|
1599
|
+
// split the string at each hyphen
|
|
1600
|
+
const parts = str.split('-');
|
|
1601
|
+
// map over the parts, capitalizing the first letter of each part
|
|
1602
|
+
const pascalParts = parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1));
|
|
1603
|
+
// join the parts together to create the final PascalCase string
|
|
1604
|
+
return pascalParts.join('');
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
class NgtCommonDirective {
|
|
1608
|
+
#vcr;
|
|
1609
|
+
#zone;
|
|
1610
|
+
#template;
|
|
1611
|
+
#view;
|
|
1612
|
+
constructor() {
|
|
1613
|
+
this.#vcr = inject(ViewContainerRef);
|
|
1614
|
+
this.#zone = inject(NgZone);
|
|
1615
|
+
this.#template = inject(TemplateRef);
|
|
1616
|
+
this.injected = false;
|
|
1617
|
+
this.shouldCreateView = true;
|
|
1618
|
+
const commentNode = this.#vcr.element.nativeElement;
|
|
1619
|
+
if (commentNode[SPECIAL_INTERNAL_ADD_COMMENT]) {
|
|
1620
|
+
commentNode[SPECIAL_INTERNAL_ADD_COMMENT]();
|
|
1621
|
+
delete commentNode[SPECIAL_INTERNAL_ADD_COMMENT];
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
createView() {
|
|
1625
|
+
if (this.shouldCreateView) {
|
|
1626
|
+
if (this.#view && !this.#view.destroyed) {
|
|
1627
|
+
this.#view.destroy();
|
|
1628
|
+
}
|
|
1629
|
+
this.#zone.runOutsideAngular(() => {
|
|
1630
|
+
this.#view = this.#vcr.createEmbeddedView(this.#template);
|
|
1631
|
+
this.#view.detectChanges();
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtCommonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1636
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtCommonDirective, ngImport: i0 }); }
|
|
1637
|
+
}
|
|
1638
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtCommonDirective, decorators: [{
|
|
1639
|
+
type: Directive
|
|
1640
|
+
}], ctorParameters: function () { return []; } });
|
|
1641
|
+
|
|
1642
|
+
class NgtArgs extends NgtCommonDirective {
|
|
1643
|
+
#injectedArgs = [];
|
|
1644
|
+
set args(args) {
|
|
1645
|
+
if (args == null || !Array.isArray(args) || (args.length === 1 && args[0] === null))
|
|
1646
|
+
return;
|
|
1647
|
+
this.injected = false;
|
|
1648
|
+
this.#injectedArgs = args;
|
|
1649
|
+
this.createView();
|
|
1650
|
+
}
|
|
1651
|
+
get args() {
|
|
1652
|
+
if (this.validate()) {
|
|
1653
|
+
this.injected = true;
|
|
1654
|
+
return this.#injectedArgs;
|
|
1655
|
+
}
|
|
1656
|
+
return null;
|
|
1657
|
+
}
|
|
1658
|
+
validate() {
|
|
1659
|
+
return !this.injected && !!this.#injectedArgs.length;
|
|
1660
|
+
}
|
|
1661
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtArgs, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1662
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtArgs, isStandalone: true, selector: "[args]", inputs: { args: "args" }, usesInheritance: true, ngImport: i0 }); }
|
|
1663
|
+
}
|
|
1664
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtArgs, decorators: [{
|
|
1665
|
+
type: Directive,
|
|
1666
|
+
args: [{ selector: '[args]', standalone: true }]
|
|
1667
|
+
}], propDecorators: { args: [{
|
|
1668
|
+
type: Input
|
|
1669
|
+
}] } });
|
|
1670
|
+
|
|
1671
|
+
class NgtParent extends NgtCommonDirective {
|
|
1672
|
+
#injectedParent = null;
|
|
1673
|
+
set parent(parent) {
|
|
1674
|
+
if (!parent)
|
|
1675
|
+
return;
|
|
1676
|
+
this.injected = false;
|
|
1677
|
+
this.#injectedParent = parent;
|
|
1678
|
+
this.createView();
|
|
1679
|
+
}
|
|
1680
|
+
get parent() {
|
|
1681
|
+
if (this.validate()) {
|
|
1682
|
+
this.injected = true;
|
|
1683
|
+
return this.#injectedParent;
|
|
1684
|
+
}
|
|
1685
|
+
return null;
|
|
1588
1686
|
}
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
const updatedCallback = (event) => {
|
|
1595
|
-
if (previousHandler)
|
|
1596
|
-
previousHandler(event);
|
|
1597
|
-
callback(event);
|
|
1598
|
-
};
|
|
1599
|
-
Object.assign(lS.handlers, { [eventName]: eventToHandler(updatedCallback, cdr, targetCdr) });
|
|
1600
|
-
// increment the count everytime
|
|
1601
|
-
lS.eventCount += 1;
|
|
1602
|
-
// but only add the instance (target) to the interaction array (so that it is handled by the EventManager with Raycast)
|
|
1603
|
-
// the first time eventCount is incremented
|
|
1604
|
-
if (lS.eventCount === 1 && instance['raycast'])
|
|
1605
|
-
lS.store.get('addInteraction')(instance);
|
|
1606
|
-
// clean up the event listener by removing the target from the interaction array
|
|
1607
|
-
return () => {
|
|
1608
|
-
const localState = getLocalState(instance);
|
|
1609
|
-
if (localState && localState.eventCount)
|
|
1610
|
-
localState.store.get('removeInteraction')(instance['uuid']);
|
|
1611
|
-
};
|
|
1612
|
-
}
|
|
1613
|
-
function eventToHandler(callback, cdr, targetCdr) {
|
|
1614
|
-
return (event) => {
|
|
1615
|
-
callback(event);
|
|
1616
|
-
safeDetectChanges(targetCdr);
|
|
1617
|
-
safeDetectChanges(cdr);
|
|
1618
|
-
};
|
|
1619
|
-
}
|
|
1620
|
-
function kebabToPascal(str) {
|
|
1621
|
-
// split the string at each hyphen
|
|
1622
|
-
const parts = str.split('-');
|
|
1623
|
-
// map over the parts, capitalizing the first letter of each part
|
|
1624
|
-
const pascalParts = parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1));
|
|
1625
|
-
// join the parts together to create the final PascalCase string
|
|
1626
|
-
return pascalParts.join('');
|
|
1687
|
+
validate() {
|
|
1688
|
+
return !this.injected && !!this.#injectedParent;
|
|
1689
|
+
}
|
|
1690
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtParent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1691
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtParent, isStandalone: true, selector: "[parent]", inputs: { parent: "parent" }, usesInheritance: true, ngImport: i0 }); }
|
|
1627
1692
|
}
|
|
1693
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtParent, decorators: [{
|
|
1694
|
+
type: Directive,
|
|
1695
|
+
args: [{ selector: '[parent]', standalone: true }]
|
|
1696
|
+
}], propDecorators: { parent: [{
|
|
1697
|
+
type: Input
|
|
1698
|
+
}] } });
|
|
1628
1699
|
|
|
1629
1700
|
class NgtRendererStore {
|
|
1701
|
+
#comments = [];
|
|
1630
1702
|
constructor(root) {
|
|
1631
1703
|
this.root = root;
|
|
1632
|
-
this.comments = [];
|
|
1633
1704
|
}
|
|
1634
1705
|
createNode(type, node) {
|
|
1635
1706
|
const state = [
|
|
@@ -1662,12 +1733,12 @@ class NgtRendererStore {
|
|
|
1662
1733
|
// we attach an arrow function to the Comment node
|
|
1663
1734
|
// In our directives, we can call this function to then start tracking the RendererNode
|
|
1664
1735
|
// this is done to limit the amount of Nodes we need to process for getCreationState
|
|
1665
|
-
rendererNode[
|
|
1736
|
+
rendererNode[SPECIAL_INTERNAL_ADD_COMMENT] = (node) => {
|
|
1666
1737
|
if (node && node.__ngt_renderer__[0 /* NgtRendererClassId.type */] === 'portal') {
|
|
1667
1738
|
this.portals.push(node);
|
|
1668
1739
|
}
|
|
1669
1740
|
else {
|
|
1670
|
-
this
|
|
1741
|
+
this.#comments.push(rendererNode);
|
|
1671
1742
|
}
|
|
1672
1743
|
};
|
|
1673
1744
|
return rendererNode;
|
|
@@ -1786,7 +1857,7 @@ class NgtRendererStore {
|
|
|
1786
1857
|
value.nativeElement = node;
|
|
1787
1858
|
return;
|
|
1788
1859
|
}
|
|
1789
|
-
const parent = getLocalState(node).parent || rS[1 /* NgtRendererClassId.parent */];
|
|
1860
|
+
const parent = getLocalState(node).parent() || rS[1 /* NgtRendererClassId.parent */];
|
|
1790
1861
|
// [rawValue]
|
|
1791
1862
|
if (getLocalState(node).isRaw && name === SPECIAL_PROPERTIES.VALUE) {
|
|
1792
1863
|
rS[11 /* NgtRendererClassId.rawValue */] = value;
|
|
@@ -1821,9 +1892,6 @@ class NgtRendererStore {
|
|
|
1821
1892
|
get rootScene() {
|
|
1822
1893
|
return this.root.store.get('scene');
|
|
1823
1894
|
}
|
|
1824
|
-
get rootCdr() {
|
|
1825
|
-
return this.root.cdr;
|
|
1826
|
-
}
|
|
1827
1895
|
get portals() {
|
|
1828
1896
|
return this.root.portals;
|
|
1829
1897
|
}
|
|
@@ -1878,12 +1946,10 @@ class NgtRendererStore {
|
|
|
1878
1946
|
rS[6 /* NgtRendererClassId.compoundParent */] = undefined;
|
|
1879
1947
|
const localState = getLocalState(node);
|
|
1880
1948
|
if (localState.objects) {
|
|
1881
|
-
localState.objects.
|
|
1882
|
-
localState.objects.complete();
|
|
1949
|
+
untracked(localState.objects).forEach((obj) => this.destroy(obj, parent));
|
|
1883
1950
|
}
|
|
1884
1951
|
if (localState.nonObjects) {
|
|
1885
|
-
localState.nonObjects.
|
|
1886
|
-
localState.nonObjects.complete();
|
|
1952
|
+
untracked(localState.nonObjects).forEach((obj) => this.destroy(obj, parent));
|
|
1887
1953
|
}
|
|
1888
1954
|
if (localState.afterUpdate)
|
|
1889
1955
|
localState.afterUpdate.complete();
|
|
@@ -1903,10 +1969,10 @@ class NgtRendererStore {
|
|
|
1903
1969
|
}
|
|
1904
1970
|
if (rS[0 /* NgtRendererClassId.type */] === 'comment') {
|
|
1905
1971
|
rS[14 /* NgtRendererClassId.injectorFactory */] = null;
|
|
1906
|
-
delete node[
|
|
1907
|
-
const index = this
|
|
1972
|
+
delete node[SPECIAL_INTERNAL_ADD_COMMENT];
|
|
1973
|
+
const index = this.#comments.findIndex((comment) => comment === node);
|
|
1908
1974
|
if (index > -1) {
|
|
1909
|
-
this
|
|
1975
|
+
this.#comments.splice(index, 1);
|
|
1910
1976
|
}
|
|
1911
1977
|
}
|
|
1912
1978
|
if (rS[0 /* NgtRendererClassId.type */] === 'portal') {
|
|
@@ -1945,9 +2011,9 @@ class NgtRendererStore {
|
|
|
1945
2011
|
}
|
|
1946
2012
|
firstNonInjectedDirective(dir) {
|
|
1947
2013
|
let directive;
|
|
1948
|
-
let i = this
|
|
2014
|
+
let i = this.#comments.length - 1;
|
|
1949
2015
|
while (i >= 0) {
|
|
1950
|
-
const comment = this
|
|
2016
|
+
const comment = this.#comments[i];
|
|
1951
2017
|
if (comment.__ngt_renderer__[4 /* NgtRendererClassId.destroyed */]) {
|
|
1952
2018
|
i--;
|
|
1953
2019
|
continue;
|
|
@@ -1995,33 +2061,35 @@ class NgtRendererStore {
|
|
|
1995
2061
|
}
|
|
1996
2062
|
|
|
1997
2063
|
class NgtRendererFactory {
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
}
|
|
2064
|
+
#delegateRendererFactory = inject(RendererFactory2, { skipSelf: true });
|
|
2065
|
+
#catalogue = inject(NGT_CATALOGUE);
|
|
2066
|
+
#zone = inject(NgZone);
|
|
2067
|
+
#cdr = inject(ChangeDetectorRef);
|
|
2068
|
+
#rendererMap = new Map();
|
|
2069
|
+
#routedSet = new Set();
|
|
2070
|
+
// all Renderer instances share the same Store
|
|
2071
|
+
#rendererStore = new NgtRendererStore({
|
|
2072
|
+
portals: [],
|
|
2073
|
+
store: inject(NgtStore),
|
|
2074
|
+
compoundPrefixes: inject(NGT_COMPOUND_PREFIXES),
|
|
2075
|
+
document: inject(DOCUMENT),
|
|
2076
|
+
});
|
|
2012
2077
|
createRenderer(hostElement, type) {
|
|
2013
|
-
const delegateRenderer = this
|
|
2078
|
+
const delegateRenderer = this.#delegateRendererFactory.createRenderer(hostElement, type);
|
|
2014
2079
|
if (!type)
|
|
2015
2080
|
return delegateRenderer;
|
|
2016
|
-
if (type['type']['
|
|
2017
|
-
|
|
2081
|
+
// if ((type as NgtAnyRecord)['type']['isHtml']) {
|
|
2082
|
+
// return delegateRenderer;
|
|
2083
|
+
// }
|
|
2084
|
+
if (type['type'][ROUTED_SCENE]) {
|
|
2085
|
+
this.#routedSet.add(type.id);
|
|
2018
2086
|
}
|
|
2019
|
-
let renderer = this
|
|
2087
|
+
let renderer = this.#rendererMap.get(type.id);
|
|
2020
2088
|
if (!renderer) {
|
|
2021
|
-
renderer = new NgtRenderer(delegateRenderer, this
|
|
2089
|
+
renderer = new NgtRenderer(delegateRenderer, this.#rendererStore, this.#catalogue, this.#zone, this.#cdr,
|
|
2022
2090
|
// setting root scene if there's no routed scene OR this component is the routed Scene
|
|
2023
|
-
!hostElement && (this
|
|
2024
|
-
this
|
|
2091
|
+
!hostElement && (this.#routedSet.size === 0 || this.#routedSet.has(type.id)));
|
|
2092
|
+
this.#rendererMap.set(type.id, renderer);
|
|
2025
2093
|
}
|
|
2026
2094
|
return renderer;
|
|
2027
2095
|
}
|
|
@@ -2035,10 +2103,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
|
|
|
2035
2103
|
* Anything abbreviated with rS/RS stands for RendererState
|
|
2036
2104
|
*/
|
|
2037
2105
|
class NgtRenderer {
|
|
2038
|
-
constructor(delegate, store, catalogue, root = true) {
|
|
2106
|
+
constructor(delegate, store, catalogue, zone, cdr, root = true) {
|
|
2039
2107
|
this.delegate = delegate;
|
|
2040
2108
|
this.store = store;
|
|
2041
2109
|
this.catalogue = catalogue;
|
|
2110
|
+
this.zone = zone;
|
|
2111
|
+
this.cdr = cdr;
|
|
2042
2112
|
this.root = root;
|
|
2043
2113
|
this.createText = this.delegate.createText.bind(this.delegate);
|
|
2044
2114
|
this.destroy = this.delegate.destroy.bind(this.delegate);
|
|
@@ -2135,11 +2205,20 @@ class NgtRenderer {
|
|
|
2135
2205
|
}
|
|
2136
2206
|
if (cRS[2 /* NgtRendererClassId.injectedParent */]) {
|
|
2137
2207
|
if (is.ref(cRS[2 /* NgtRendererClassId.injectedParent */])) {
|
|
2138
|
-
cRS[
|
|
2139
|
-
|
|
2140
|
-
|
|
2208
|
+
const injector = cRS[14 /* NgtRendererClassId.injectorFactory */]().get(Injector, null);
|
|
2209
|
+
if (!injector) {
|
|
2210
|
+
console.warn(`[NGT] NgtRenderer is attempting to start an effect for injectedParent but no Injector is found.`);
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
const watcher = effect(() => {
|
|
2214
|
+
const injectedParent = cRS[2 /* NgtRendererClassId.injectedParent */].nativeElement;
|
|
2215
|
+
if (injectedParent && injectedParent !== parent) {
|
|
2216
|
+
this.appendChild(injectedParent, newChild);
|
|
2217
|
+
// only run this effect once
|
|
2218
|
+
// as soon as we re-run appendChild with the injectedParent, we stop the effect
|
|
2219
|
+
watcher.destroy();
|
|
2141
2220
|
}
|
|
2142
|
-
});
|
|
2221
|
+
}, { injector, manualCleanup: true });
|
|
2143
2222
|
return;
|
|
2144
2223
|
}
|
|
2145
2224
|
else if (parent !== cRS[2 /* NgtRendererClassId.injectedParent */]) {
|
|
@@ -2168,7 +2247,7 @@ class NgtRenderer {
|
|
|
2168
2247
|
// if both are three instances, straightforward case
|
|
2169
2248
|
if (pRS[0 /* NgtRendererClassId.type */] === 'three' && cRS[0 /* NgtRendererClassId.type */] === 'three') {
|
|
2170
2249
|
// if child already attached to a parent, skip
|
|
2171
|
-
if (getLocalState(newChild).parent)
|
|
2250
|
+
if (getLocalState(newChild).parent && untracked(getLocalState(newChild).parent))
|
|
2172
2251
|
return;
|
|
2173
2252
|
// attach THREE child
|
|
2174
2253
|
attachThreeChild(parent, newChild);
|
|
@@ -2208,7 +2287,7 @@ class NgtRenderer {
|
|
|
2208
2287
|
}
|
|
2209
2288
|
const shouldFindGrandparentInstance =
|
|
2210
2289
|
// if child is three but haven't been attached to a parent yet
|
|
2211
|
-
(cRS[0 /* NgtRendererClassId.type */] === 'three' && !getLocalState(newChild).parent) ||
|
|
2290
|
+
(cRS[0 /* NgtRendererClassId.type */] === 'three' && !untracked(getLocalState(newChild).parent)) ||
|
|
2212
2291
|
// or both parent and child are DOM elements
|
|
2213
2292
|
// or they are compound AND haven't had a THREE instance yet
|
|
2214
2293
|
((pRS[0 /* NgtRendererClassId.type */] === 'dom' ||
|
|
@@ -2223,7 +2302,7 @@ class NgtRenderer {
|
|
|
2223
2302
|
}
|
|
2224
2303
|
}
|
|
2225
2304
|
insertBefore(parent, newChild
|
|
2226
|
-
// TODO
|
|
2305
|
+
// TODO: we might need these?
|
|
2227
2306
|
// refChild: NgtRendererNode
|
|
2228
2307
|
// isMove?: boolean | undefined
|
|
2229
2308
|
) {
|
|
@@ -2295,33 +2374,23 @@ class NgtRenderer {
|
|
|
2295
2374
|
}
|
|
2296
2375
|
listen(target, eventName, callback) {
|
|
2297
2376
|
const rS = target.__ngt_renderer__;
|
|
2298
|
-
|
|
2377
|
+
// if the target doesn't have __ngt_renderer__, we delegate
|
|
2378
|
+
// if target is DOM node, then we pass that to delegate Renderer
|
|
2379
|
+
if (!rS || this.store.isDOM(target)) {
|
|
2380
|
+
return this.delegate.listen(target, eventName, callback);
|
|
2381
|
+
}
|
|
2299
2382
|
if (rS[0 /* NgtRendererClassId.type */] === 'three' ||
|
|
2300
2383
|
(rS[0 /* NgtRendererClassId.type */] === 'compound' && rS[7 /* NgtRendererClassId.compounded */])) {
|
|
2301
2384
|
const instance = rS[7 /* NgtRendererClassId.compounded */] || target;
|
|
2302
2385
|
const priority = getLocalState(target).priority;
|
|
2303
|
-
return processThreeEvent(instance, priority || 0, eventName, callback, this.
|
|
2386
|
+
return processThreeEvent(instance, priority || 0, eventName, callback, this.zone, this.cdr);
|
|
2304
2387
|
}
|
|
2305
2388
|
if (rS[0 /* NgtRendererClassId.type */] === 'compound' && !rS[7 /* NgtRendererClassId.compounded */]) {
|
|
2306
2389
|
this.store.queueOperation(target, [
|
|
2307
2390
|
'op',
|
|
2308
2391
|
() => this.store.queueOperation(target, ['cleanUp', this.listen(target, eventName, callback)]),
|
|
2309
2392
|
]);
|
|
2310
|
-
|
|
2311
|
-
// setup a new callback with CDR so that it will trigger change detection properly
|
|
2312
|
-
const callbackWithCdr = (event) => {
|
|
2313
|
-
const value = callback(event);
|
|
2314
|
-
safeDetectChanges(targetCdr);
|
|
2315
|
-
safeDetectChanges(this.store.rootCdr);
|
|
2316
|
-
return value;
|
|
2317
|
-
};
|
|
2318
|
-
// if the target doesn't have __ngt_renderer__, we delegate
|
|
2319
|
-
if (!rS) {
|
|
2320
|
-
return this.delegate.listen(target, eventName, callbackWithCdr);
|
|
2321
|
-
}
|
|
2322
|
-
// if target is DOM node, then we pass that to delegate Renderer
|
|
2323
|
-
if (this.store.isDOM(target)) {
|
|
2324
|
-
return this.delegate.listen(target, eventName, callbackWithCdr);
|
|
2393
|
+
return () => { };
|
|
2325
2394
|
}
|
|
2326
2395
|
// @ts-expect-error - we know that target is not DOM node
|
|
2327
2396
|
if (target === this.store.rootScene) {
|
|
@@ -2333,7 +2402,7 @@ class NgtRenderer {
|
|
|
2333
2402
|
const eventTarget = domTarget === 'window'
|
|
2334
2403
|
? target['ownerDocument']['defaultView']
|
|
2335
2404
|
: target['ownerDocument'];
|
|
2336
|
-
return this.delegate.listen(eventTarget, event,
|
|
2405
|
+
return this.delegate.listen(eventTarget, event, callback);
|
|
2337
2406
|
}
|
|
2338
2407
|
return () => { };
|
|
2339
2408
|
}
|
|
@@ -2352,105 +2421,18 @@ function provideNgtRenderer({ store, changeDetectorRef, compoundPrefixes = [] })
|
|
|
2352
2421
|
{ provide: NgtStore, useValue: store },
|
|
2353
2422
|
{ provide: ChangeDetectorRef, useValue: changeDetectorRef },
|
|
2354
2423
|
{ provide: NGT_COMPOUND_PREFIXES, useValue: compoundPrefixes },
|
|
2424
|
+
provideZoneChangeDetection({ runCoalescing: true, eventCoalescing: true }),
|
|
2355
2425
|
]);
|
|
2356
2426
|
}
|
|
2357
2427
|
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
pointermove: true,
|
|
2367
|
-
pointercancel: true,
|
|
2368
|
-
lostpointercapture: true,
|
|
2369
|
-
};
|
|
2370
|
-
const supportedEvents = [
|
|
2371
|
-
'click',
|
|
2372
|
-
'contextmenu',
|
|
2373
|
-
'dblclick',
|
|
2374
|
-
'pointerup',
|
|
2375
|
-
'pointerdown',
|
|
2376
|
-
'pointerover',
|
|
2377
|
-
'pointerout',
|
|
2378
|
-
'pointerenter',
|
|
2379
|
-
'pointerleave',
|
|
2380
|
-
'pointermove',
|
|
2381
|
-
'pointermissed',
|
|
2382
|
-
'pointercancel',
|
|
2383
|
-
'wheel',
|
|
2384
|
-
];
|
|
2385
|
-
function createPointerEvents(store) {
|
|
2386
|
-
const { handlePointer } = createEvents(store);
|
|
2387
|
-
return {
|
|
2388
|
-
priority: 1,
|
|
2389
|
-
enabled: true,
|
|
2390
|
-
compute: (event, root) => {
|
|
2391
|
-
const state = root.get();
|
|
2392
|
-
// https://github.com/pmndrs/react-three-fiber/pull/782
|
|
2393
|
-
// Events trigger outside of canvas when moved, use offsetX/Y by default and allow overrides
|
|
2394
|
-
state.pointer.set((event.offsetX / state.size.width) * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
2395
|
-
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
2396
|
-
},
|
|
2397
|
-
connected: undefined,
|
|
2398
|
-
handlers: Object.keys(DOM_EVENTS).reduce((handlers, supportedEventName) => {
|
|
2399
|
-
handlers[supportedEventName] = handlePointer(supportedEventName);
|
|
2400
|
-
return handlers;
|
|
2401
|
-
}, {}),
|
|
2402
|
-
connect: (target) => {
|
|
2403
|
-
const state = store.get();
|
|
2404
|
-
state.events.disconnect?.();
|
|
2405
|
-
state.setEvents({ connected: target });
|
|
2406
|
-
Object.entries(state.events.handlers ?? {}).forEach(([eventName, eventHandler]) => {
|
|
2407
|
-
const passive = DOM_EVENTS[eventName];
|
|
2408
|
-
target.addEventListener(eventName, eventHandler, { passive });
|
|
2409
|
-
});
|
|
2410
|
-
},
|
|
2411
|
-
disconnect: () => {
|
|
2412
|
-
const { events, setEvents } = store.get();
|
|
2413
|
-
if (events.connected) {
|
|
2414
|
-
Object.entries(events.handlers ?? {}).forEach(([eventName, eventHandler]) => {
|
|
2415
|
-
if (events.connected instanceof HTMLElement) {
|
|
2416
|
-
events.connected.removeEventListener(eventName, eventHandler);
|
|
2417
|
-
}
|
|
2418
|
-
});
|
|
2419
|
-
setEvents({ connected: undefined });
|
|
2420
|
-
}
|
|
2421
|
-
},
|
|
2422
|
-
};
|
|
2423
|
-
}
|
|
2424
|
-
|
|
2425
|
-
class NgtCanvas extends NgtRxStore {
|
|
2426
|
-
constructor() {
|
|
2427
|
-
super(...arguments);
|
|
2428
|
-
this.cdr = inject(ChangeDetectorRef);
|
|
2429
|
-
this.envInjector = inject(EnvironmentInjector);
|
|
2430
|
-
this.host = inject(ElementRef);
|
|
2431
|
-
this.store = inject(NgtStore);
|
|
2432
|
-
this.hbClass = true;
|
|
2433
|
-
this.sceneGraphInputs = {};
|
|
2434
|
-
this.compoundPrefixes = [];
|
|
2435
|
-
this.created = new EventEmitter();
|
|
2436
|
-
this.pointerMissed = new EventEmitter();
|
|
2437
|
-
}
|
|
2438
|
-
initialize() {
|
|
2439
|
-
super.initialize();
|
|
2440
|
-
this.set({
|
|
2441
|
-
shadows: false,
|
|
2442
|
-
linear: false,
|
|
2443
|
-
flat: false,
|
|
2444
|
-
legacy: false,
|
|
2445
|
-
orthographic: false,
|
|
2446
|
-
frameloop: 'always',
|
|
2447
|
-
dpr: [1, 2],
|
|
2448
|
-
events: createPointerEvents,
|
|
2449
|
-
});
|
|
2450
|
-
}
|
|
2451
|
-
get hbPointerEvents() {
|
|
2452
|
-
return this.get('eventSource') !== this.host.nativeElement ? 'none' : 'auto';
|
|
2453
|
-
}
|
|
2428
|
+
class NgtCanvas extends NgtSignalStore {
|
|
2429
|
+
#envInjector;
|
|
2430
|
+
#injector;
|
|
2431
|
+
#host;
|
|
2432
|
+
#zone;
|
|
2433
|
+
#cdr;
|
|
2434
|
+
#store;
|
|
2435
|
+
#isReady;
|
|
2454
2436
|
set linear(linear) {
|
|
2455
2437
|
this.set({ linear });
|
|
2456
2438
|
}
|
|
@@ -2473,13 +2455,14 @@ class NgtCanvas extends NgtRxStore {
|
|
|
2473
2455
|
this.set({ raycaster });
|
|
2474
2456
|
}
|
|
2475
2457
|
set shadows(shadows) {
|
|
2476
|
-
this.set({
|
|
2477
|
-
shadows: typeof shadows === 'object' ? shadows : shadows,
|
|
2478
|
-
});
|
|
2458
|
+
this.set({ shadows });
|
|
2479
2459
|
}
|
|
2480
2460
|
set camera(camera) {
|
|
2481
2461
|
this.set({ camera });
|
|
2482
2462
|
}
|
|
2463
|
+
set scene(scene) {
|
|
2464
|
+
this.set({ scene });
|
|
2465
|
+
}
|
|
2483
2466
|
set gl(gl) {
|
|
2484
2467
|
this.set({ gl });
|
|
2485
2468
|
}
|
|
@@ -2495,43 +2478,96 @@ class NgtCanvas extends NgtRxStore {
|
|
|
2495
2478
|
set performance(performance) {
|
|
2496
2479
|
this.set({ performance });
|
|
2497
2480
|
}
|
|
2481
|
+
#glRef;
|
|
2482
|
+
#glEnvInjector;
|
|
2483
|
+
constructor() {
|
|
2484
|
+
super({
|
|
2485
|
+
shadows: false,
|
|
2486
|
+
linear: false,
|
|
2487
|
+
flat: false,
|
|
2488
|
+
legacy: false,
|
|
2489
|
+
orthographic: false,
|
|
2490
|
+
frameloop: 'always',
|
|
2491
|
+
dpr: [1, 2],
|
|
2492
|
+
events: createPointerEvents,
|
|
2493
|
+
});
|
|
2494
|
+
this.#envInjector = inject(EnvironmentInjector);
|
|
2495
|
+
this.#injector = inject(Injector);
|
|
2496
|
+
this.#host = inject(ElementRef);
|
|
2497
|
+
this.#zone = inject(NgZone);
|
|
2498
|
+
this.#cdr = inject(ChangeDetectorRef);
|
|
2499
|
+
this.#store = inject(NgtStore);
|
|
2500
|
+
this.#isReady = this.#store.select('ready');
|
|
2501
|
+
this.sceneGraphInputs = {};
|
|
2502
|
+
this.compoundPrefixes = [];
|
|
2503
|
+
this.created = new EventEmitter();
|
|
2504
|
+
this.pointerMissed = new EventEmitter();
|
|
2505
|
+
inject(DestroyRef).onDestroy(() => {
|
|
2506
|
+
if (this.#glRef)
|
|
2507
|
+
this.#glRef.destroy();
|
|
2508
|
+
if (this.#glEnvInjector)
|
|
2509
|
+
this.#glEnvInjector.destroy();
|
|
2510
|
+
injectNgtLoader.destroy();
|
|
2511
|
+
this.#store.destroy(this.glCanvas.nativeElement);
|
|
2512
|
+
});
|
|
2513
|
+
}
|
|
2514
|
+
get hbPointerEvents() {
|
|
2515
|
+
return this.select('eventSource')() !== this.#host.nativeElement ? 'none' : 'auto';
|
|
2516
|
+
}
|
|
2498
2517
|
ngOnChanges(changes) {
|
|
2499
|
-
if (changes['sceneGraphInputs'] && this
|
|
2500
|
-
this
|
|
2518
|
+
if (changes['sceneGraphInputs'] && !changes['sceneGraphInputs'].firstChange && this.#glRef) {
|
|
2519
|
+
this.#setSceneGraphInputs();
|
|
2501
2520
|
}
|
|
2502
2521
|
}
|
|
2503
2522
|
ngOnInit() {
|
|
2504
2523
|
if (!this.get('eventSource')) {
|
|
2505
2524
|
// set default event source to the host element
|
|
2506
|
-
this.eventSource
|
|
2525
|
+
this.set({ eventSource: this.#host.nativeElement });
|
|
2507
2526
|
}
|
|
2508
2527
|
if (this.pointerMissed.observed) {
|
|
2509
|
-
this
|
|
2528
|
+
this.#store.set({
|
|
2510
2529
|
onPointerMissed: (event) => {
|
|
2511
2530
|
this.pointerMissed.emit(event);
|
|
2512
|
-
safeDetectChanges(this.cdr);
|
|
2513
2531
|
},
|
|
2514
2532
|
});
|
|
2515
2533
|
}
|
|
2516
2534
|
// setup NgtStore
|
|
2517
|
-
this
|
|
2535
|
+
this.#store.init();
|
|
2518
2536
|
// set rootStateMap
|
|
2519
|
-
rootStateMap.set(this.glCanvas.nativeElement, this
|
|
2537
|
+
rootStateMap.set(this.glCanvas.nativeElement, this.#store);
|
|
2520
2538
|
// subscribe to store to listen for ready state
|
|
2521
|
-
|
|
2539
|
+
effect(() => {
|
|
2540
|
+
this.#zone.runOutsideAngular(() => {
|
|
2541
|
+
if (this.#isReady())
|
|
2542
|
+
this.#storeReady();
|
|
2543
|
+
});
|
|
2544
|
+
}, { injector: this.#injector, allowSignalWrites: true });
|
|
2522
2545
|
}
|
|
2523
|
-
|
|
2546
|
+
#resizeRef;
|
|
2547
|
+
// NOTE: this is invoked outside of Angular Zone
|
|
2548
|
+
onResize({ width, height, top, left }) {
|
|
2549
|
+
// destroy previous effect
|
|
2550
|
+
if (this.#resizeRef) {
|
|
2551
|
+
this.#resizeRef.destroy();
|
|
2552
|
+
}
|
|
2524
2553
|
if (width > 0 && height > 0) {
|
|
2525
|
-
if (!this
|
|
2526
|
-
this
|
|
2527
|
-
this.
|
|
2554
|
+
if (!this.#store.isInit)
|
|
2555
|
+
this.#store.init();
|
|
2556
|
+
const inputs = this.select();
|
|
2557
|
+
this.#resizeRef = this.#zone.run(() => effect(() => {
|
|
2558
|
+
const canvasInputs = inputs();
|
|
2559
|
+
this.#zone.runOutsideAngular(() => {
|
|
2560
|
+
this.#store.configure({ ...canvasInputs, size: { width, height, top, left } }, this.glCanvas.nativeElement);
|
|
2561
|
+
});
|
|
2562
|
+
}, { injector: this.#injector, manualCleanup: true, allowSignalWrites: true }));
|
|
2528
2563
|
}
|
|
2529
2564
|
}
|
|
2530
|
-
|
|
2565
|
+
// NOTE: This is invoked outside of Angular Zone
|
|
2566
|
+
#storeReady() {
|
|
2531
2567
|
// canvas is ready, let's activate the loop
|
|
2532
|
-
this
|
|
2568
|
+
this.#store.set((state) => ({ internal: { ...state.internal, active: true } }));
|
|
2533
2569
|
const inputs = this.get();
|
|
2534
|
-
const state = this
|
|
2570
|
+
const state = this.#store.get();
|
|
2535
2571
|
// connect to event source
|
|
2536
2572
|
state.events.connect?.(is.ref(inputs.eventSource) ? inputs.eventSource.nativeElement : inputs.eventSource);
|
|
2537
2573
|
// setup compute function for events
|
|
@@ -2547,68 +2583,73 @@ class NgtCanvas extends NgtRxStore {
|
|
|
2547
2583
|
});
|
|
2548
2584
|
}
|
|
2549
2585
|
// emit created event if observed
|
|
2550
|
-
if (this.created.observed)
|
|
2551
|
-
|
|
2586
|
+
if (this.created.observed) {
|
|
2587
|
+
// but go back into zone to run it
|
|
2588
|
+
this.#zone.run(() => {
|
|
2589
|
+
this.created.emit(this.#store.get());
|
|
2590
|
+
});
|
|
2591
|
+
}
|
|
2552
2592
|
// render
|
|
2553
|
-
if (this
|
|
2554
|
-
this
|
|
2593
|
+
if (this.#glRef)
|
|
2594
|
+
this.#glRef.destroy();
|
|
2555
2595
|
requestAnimationFrame(() => {
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
this
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2596
|
+
this.#glEnvInjector = createEnvironmentInjector([
|
|
2597
|
+
provideNgtRenderer({
|
|
2598
|
+
store: this.#store,
|
|
2599
|
+
changeDetectorRef: this.#cdr,
|
|
2600
|
+
compoundPrefixes: this.compoundPrefixes,
|
|
2601
|
+
}),
|
|
2602
|
+
], this.#envInjector);
|
|
2603
|
+
this.#glRef = this.glAnchor.createComponent(this.sceneGraph, {
|
|
2604
|
+
environmentInjector: this.#glEnvInjector,
|
|
2605
|
+
});
|
|
2606
|
+
this.#setSceneGraphInputs();
|
|
2607
|
+
this.#overrideChangeDetectorRef();
|
|
2608
|
+
safeDetectChanges(this.#cdr);
|
|
2566
2609
|
});
|
|
2567
2610
|
}
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
if (this.glEnvInjector)
|
|
2572
|
-
this.glEnvInjector.destroy();
|
|
2573
|
-
injectNgtLoader.destroy();
|
|
2574
|
-
this.store.destroy(this.glCanvas.nativeElement);
|
|
2575
|
-
super.ngOnDestroy();
|
|
2576
|
-
}
|
|
2577
|
-
overrideDetectChanges() {
|
|
2578
|
-
const originalDetectChanges = this.cdr.detectChanges.bind(this.cdr);
|
|
2579
|
-
this.cdr.detectChanges = () => {
|
|
2611
|
+
#overrideChangeDetectorRef() {
|
|
2612
|
+
const originalDetectChanges = this.#cdr.detectChanges.bind(this.#cdr);
|
|
2613
|
+
this.#cdr.detectChanges = () => {
|
|
2580
2614
|
originalDetectChanges();
|
|
2581
|
-
safeDetectChanges(this
|
|
2615
|
+
safeDetectChanges(this.#glRef?.changeDetectorRef);
|
|
2582
2616
|
};
|
|
2583
2617
|
}
|
|
2584
|
-
setSceneGraphInputs() {
|
|
2585
|
-
|
|
2586
|
-
this
|
|
2587
|
-
|
|
2588
|
-
|
|
2618
|
+
#setSceneGraphInputs() {
|
|
2619
|
+
this.#zone.run(() => {
|
|
2620
|
+
if (this.#glRef) {
|
|
2621
|
+
for (const [key, value] of Object.entries(this.sceneGraphInputs)) {
|
|
2622
|
+
this.#glRef.setInput(key, value);
|
|
2623
|
+
}
|
|
2624
|
+
safeDetectChanges(this.#glRef.changeDetectorRef);
|
|
2625
|
+
}
|
|
2626
|
+
});
|
|
2589
2627
|
}
|
|
2590
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtCanvas, deps:
|
|
2591
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.0", type: NgtCanvas, isStandalone: true, selector: "ngt-canvas", inputs: { sceneGraph: "sceneGraph", sceneGraphInputs: "sceneGraphInputs", compoundPrefixes: "compoundPrefixes", linear: "linear", legacy: "legacy", flat: "flat", orthographic: "orthographic", frameloop: "frameloop", dpr: "dpr", raycaster: "raycaster", shadows: "shadows", camera: "camera", gl: "gl", eventSource: "eventSource", eventPrefix: "eventPrefix", lookAt: "lookAt", performance: "performance" }, outputs: { created: "created", pointerMissed: "pointerMissed" }, host: {
|
|
2628
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtCanvas, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2629
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.0", type: NgtCanvas, isStandalone: true, selector: "ngt-canvas", inputs: { sceneGraph: "sceneGraph", sceneGraphInputs: "sceneGraphInputs", compoundPrefixes: "compoundPrefixes", linear: "linear", legacy: "legacy", flat: "flat", orthographic: "orthographic", frameloop: "frameloop", dpr: "dpr", raycaster: "raycaster", shadows: "shadows", camera: "camera", scene: "scene", gl: "gl", eventSource: "eventSource", eventPrefix: "eventPrefix", lookAt: "lookAt", performance: "performance" }, outputs: { created: "created", pointerMissed: "pointerMissed" }, host: { styleAttribute: "display: block;position: relative;width: 100%;height: 100%;overflow: hidden;" }, providers: [NgtStore, provideNgxResizeOptions({ emitInZone: false, emitInitialResult: true })], viewQueries: [{ propertyName: "glCanvas", first: true, predicate: ["glCanvas"], descendants: true, static: true }, { propertyName: "glAnchor", first: true, predicate: ["glCanvas"], descendants: true, read: ViewContainerRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
|
|
2592
2630
|
<div (ngxResize)="onResize($event)" style="height: 100%; width: 100%;">
|
|
2593
|
-
<canvas #glCanvas style="display: block;"
|
|
2631
|
+
<canvas #glCanvas style="display: block;"> </canvas>
|
|
2594
2632
|
</div>
|
|
2595
|
-
`, isInline: true,
|
|
2633
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgxResize, selector: "[ngxResize]", inputs: ["ngxResizeOptions"], outputs: ["ngxResize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2596
2634
|
}
|
|
2597
2635
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtCanvas, decorators: [{
|
|
2598
2636
|
type: Component,
|
|
2599
|
-
args: [{
|
|
2637
|
+
args: [{
|
|
2638
|
+
selector: 'ngt-canvas',
|
|
2639
|
+
standalone: true,
|
|
2640
|
+
template: `
|
|
2600
2641
|
<div (ngxResize)="onResize($event)" style="height: 100%; width: 100%;">
|
|
2601
|
-
<canvas #glCanvas style="display: block;"
|
|
2642
|
+
<canvas #glCanvas style="display: block;"> </canvas>
|
|
2602
2643
|
</div>
|
|
2603
|
-
`,
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2644
|
+
`,
|
|
2645
|
+
imports: [NgxResize],
|
|
2646
|
+
providers: [NgtStore, provideNgxResizeOptions({ emitInZone: false, emitInitialResult: true })],
|
|
2647
|
+
host: { style: 'display: block;position: relative;width: 100%;height: 100%;overflow: hidden;' },
|
|
2648
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2649
|
+
}]
|
|
2650
|
+
}], ctorParameters: function () { return []; }, propDecorators: { sceneGraph: [{
|
|
2651
|
+
type: Input,
|
|
2652
|
+
args: [{ required: true }]
|
|
2612
2653
|
}], sceneGraphInputs: [{
|
|
2613
2654
|
type: Input
|
|
2614
2655
|
}], compoundPrefixes: [{
|
|
@@ -2631,6 +2672,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
|
|
|
2631
2672
|
type: Input
|
|
2632
2673
|
}], camera: [{
|
|
2633
2674
|
type: Input
|
|
2675
|
+
}], scene: [{
|
|
2676
|
+
type: Input
|
|
2634
2677
|
}], gl: [{
|
|
2635
2678
|
type: Input
|
|
2636
2679
|
}], eventSource: [{
|
|
@@ -2653,135 +2696,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
|
|
|
2653
2696
|
args: ['glCanvas', { static: true, read: ViewContainerRef }]
|
|
2654
2697
|
}] } });
|
|
2655
2698
|
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
function injectNgtDestroy(cb) {
|
|
2660
|
-
try {
|
|
2661
|
-
const cdr = inject(ChangeDetectorRef);
|
|
2662
|
-
const destroy$ = new ReplaySubject();
|
|
2663
|
-
queueMicrotask(() => {
|
|
2664
|
-
cdr.onDestroy(() => {
|
|
2665
|
-
destroy$.next();
|
|
2666
|
-
destroy$.complete();
|
|
2667
|
-
cb?.();
|
|
2668
|
-
});
|
|
2669
|
-
});
|
|
2670
|
-
return { destroy$, cdr };
|
|
2671
|
-
}
|
|
2672
|
-
catch (e) {
|
|
2673
|
-
throw new Error(`[NGT] injectNgtDestroy is being called outside of Constructor Context`);
|
|
2674
|
-
}
|
|
2675
|
-
}
|
|
2676
|
-
|
|
2677
|
-
function injectBeforeRender(cb, priority = 0) {
|
|
2678
|
-
try {
|
|
2699
|
+
function injectBeforeRender(cb, { priority = 0, injector = inject(Injector, { optional: true }), } = {}) {
|
|
2700
|
+
!injector && assertInInjectionContext(injectBeforeRender);
|
|
2701
|
+
return runInInjectionContext(injector, () => {
|
|
2679
2702
|
const store = inject(NgtStore);
|
|
2680
2703
|
const sub = store.get('internal').subscribe(cb, priority, store);
|
|
2681
|
-
|
|
2704
|
+
inject(DestroyRef).onDestroy(() => void sub());
|
|
2682
2705
|
return sub;
|
|
2683
|
-
}
|
|
2684
|
-
catch (e) {
|
|
2685
|
-
throw new Error(`[NGT] "injectBeforeRender" is invoked outside of Constructor Context`);
|
|
2686
|
-
}
|
|
2687
|
-
}
|
|
2688
|
-
|
|
2689
|
-
function injectNgtRef(initialValue = null) {
|
|
2690
|
-
const ref = is.ref(initialValue) ? initialValue : new ElementRef(initialValue);
|
|
2691
|
-
let lastValue = ref.nativeElement;
|
|
2692
|
-
const cdRefs = [];
|
|
2693
|
-
const ref$ = new BehaviorSubject(lastValue);
|
|
2694
|
-
const { destroy$, cdr } = injectNgtDestroy(() => void ref$.complete());
|
|
2695
|
-
cdRefs.push(cdr);
|
|
2696
|
-
const obs$ = ref$.asObservable().pipe(distinctUntilChanged(), takeUntil(destroy$));
|
|
2697
|
-
const subscribe = (callback) => obs$.subscribe((current) => {
|
|
2698
|
-
callback(current, lastValue);
|
|
2699
|
-
lastValue = current;
|
|
2700
|
-
});
|
|
2701
|
-
const useCDR = (cdr) => void cdRefs.push(cdr);
|
|
2702
|
-
const $ = obs$.pipe(filter((value, index) => index > 0 || value != null), takeUntil(destroy$));
|
|
2703
|
-
const children$ = (type = 'objects') => $.pipe(switchMap((instance) => {
|
|
2704
|
-
const localState = getLocalState(instance);
|
|
2705
|
-
if (localState.objects && localState.nonObjects) {
|
|
2706
|
-
return merge(localState.objects, localState.nonObjects).pipe(map(() => {
|
|
2707
|
-
try {
|
|
2708
|
-
return type === 'both'
|
|
2709
|
-
? [...localState.objects.value, ...localState.nonObjects.value]
|
|
2710
|
-
: localState[type].value;
|
|
2711
|
-
}
|
|
2712
|
-
catch (e) {
|
|
2713
|
-
console.error(`[NGT] Exception in accessing children of ${instance}`);
|
|
2714
|
-
return [];
|
|
2715
|
-
}
|
|
2716
|
-
}));
|
|
2717
|
-
}
|
|
2718
|
-
return of([]);
|
|
2719
|
-
}), filter((children, index) => index > 0 || children.length > 0), takeUntil(destroy$));
|
|
2720
|
-
// here, we override nativeElement to add more functionalities to nativeElement
|
|
2721
|
-
Object.defineProperty(ref, 'nativeElement', {
|
|
2722
|
-
set: (newVal) => {
|
|
2723
|
-
if (ref.nativeElement !== newVal) {
|
|
2724
|
-
ref$.next(newVal);
|
|
2725
|
-
lastValue = ref.nativeElement;
|
|
2726
|
-
ref.nativeElement = newVal;
|
|
2727
|
-
// clone the cdRefs so we can mutate cdRefs in the loop
|
|
2728
|
-
const cds = [...cdRefs];
|
|
2729
|
-
for (let i = 0; i < cds.length; i++) {
|
|
2730
|
-
const cd = cds[i];
|
|
2731
|
-
// if a ChangeDetectorRef is destroyed, we stop tracking it and go to the next one
|
|
2732
|
-
if (cd.destroyed) {
|
|
2733
|
-
cdRefs.splice(i, 1);
|
|
2734
|
-
continue;
|
|
2735
|
-
}
|
|
2736
|
-
// during creation phase, 'context' on ViewRef will be null
|
|
2737
|
-
// we check the "context" to avoid running detectChanges during this phase.
|
|
2738
|
-
// because there's nothing to check
|
|
2739
|
-
safeDetectChanges(cd);
|
|
2740
|
-
}
|
|
2741
|
-
}
|
|
2742
|
-
},
|
|
2743
|
-
get: () => ref$.value,
|
|
2744
2706
|
});
|
|
2745
|
-
return Object.assign(ref, { subscribe, $, children$, useCDR });
|
|
2746
2707
|
}
|
|
2747
2708
|
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
tryFromNodeInjector = true;
|
|
2773
|
-
const fromNodeInjector = nodeInjector.get(...args);
|
|
2774
|
-
tryFromNodeInjector = false;
|
|
2775
|
-
return fromNodeInjector;
|
|
2776
|
-
}
|
|
2777
|
-
return null;
|
|
2778
|
-
}
|
|
2779
|
-
catch (e) {
|
|
2780
|
-
return originalGet(...args);
|
|
2709
|
+
function injectNgtRef(initial = null, injector = inject(Injector, { optional: true })) {
|
|
2710
|
+
!injector && assertInInjectionContext(injectNgtRef);
|
|
2711
|
+
return runInInjectionContext(injector, () => {
|
|
2712
|
+
const cdr = inject(ChangeDetectorRef);
|
|
2713
|
+
const ref = is.ref(initial) ? initial : new ElementRef(initial);
|
|
2714
|
+
const signalRef = signal(ref.nativeElement);
|
|
2715
|
+
const readonlySignal = signalRef.asReadonly();
|
|
2716
|
+
const cached = new Map();
|
|
2717
|
+
inject(DestroyRef).onDestroy(() => void cached.clear());
|
|
2718
|
+
const children = (type = 'objects') => {
|
|
2719
|
+
if (!cached.has(type)) {
|
|
2720
|
+
cached.set(type, computed(() => {
|
|
2721
|
+
const instance = readonlySignal();
|
|
2722
|
+
if (!instance)
|
|
2723
|
+
return [];
|
|
2724
|
+
const localState = getLocalState(instance);
|
|
2725
|
+
if (!localState.objects || !localState.nonObjects)
|
|
2726
|
+
return [];
|
|
2727
|
+
if (type === 'objects')
|
|
2728
|
+
return localState.objects();
|
|
2729
|
+
if (type === 'nonObjects')
|
|
2730
|
+
return localState.nonObjects();
|
|
2731
|
+
return [...localState.objects(), ...localState.nonObjects()];
|
|
2732
|
+
}));
|
|
2781
2733
|
}
|
|
2734
|
+
return cached.get(type);
|
|
2782
2735
|
};
|
|
2783
|
-
|
|
2784
|
-
|
|
2736
|
+
Object.defineProperty(ref, 'nativeElement', {
|
|
2737
|
+
set: (newElement) => {
|
|
2738
|
+
if (newElement !== untracked(signalRef)) {
|
|
2739
|
+
signalRef.set(newElement);
|
|
2740
|
+
safeDetectChanges(cdr);
|
|
2741
|
+
}
|
|
2742
|
+
},
|
|
2743
|
+
get: () => readonlySignal(),
|
|
2744
|
+
});
|
|
2745
|
+
return Object.assign(ref, { children });
|
|
2746
|
+
});
|
|
2785
2747
|
}
|
|
2786
2748
|
|
|
2787
2749
|
class NgtRepeat extends NgForOf {
|
|
@@ -2798,51 +2760,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
|
|
|
2798
2760
|
type: Input
|
|
2799
2761
|
}] } });
|
|
2800
2762
|
|
|
2801
|
-
function isPromise(value) {
|
|
2802
|
-
return ((value instanceof Promise || Object.prototype.toString.call(value) === '[object Promise]') &&
|
|
2803
|
-
typeof value['then'] === 'function');
|
|
2804
|
-
}
|
|
2805
|
-
class NgtPush {
|
|
2806
|
-
constructor() {
|
|
2807
|
-
this.cdr = inject(ChangeDetectorRef);
|
|
2808
|
-
this.parentCdr = inject(ChangeDetectorRef, { skipSelf: true, optional: true });
|
|
2809
|
-
this.envCdr = inject(EnvironmentInjector).get(ChangeDetectorRef, null);
|
|
2810
|
-
}
|
|
2811
|
-
transform(value, defaultValue = null) {
|
|
2812
|
-
if (this.obj === value)
|
|
2813
|
-
return this.latestValue;
|
|
2814
|
-
this.obj = value;
|
|
2815
|
-
this.latestValue = defaultValue;
|
|
2816
|
-
if (this.sub)
|
|
2817
|
-
this.sub.unsubscribe();
|
|
2818
|
-
if (isObservable(this.obj))
|
|
2819
|
-
this.sub = this.obj.subscribe(this.updateValue.bind(this));
|
|
2820
|
-
else if (isPromise(this.obj))
|
|
2821
|
-
this.obj.then(this.updateValue.bind(this));
|
|
2822
|
-
else
|
|
2823
|
-
throw new Error(`[NGT] Invalid value passed to ngtPush pipe`);
|
|
2824
|
-
return this.latestValue;
|
|
2825
|
-
}
|
|
2826
|
-
updateValue(val) {
|
|
2827
|
-
this.latestValue = val;
|
|
2828
|
-
safeDetectChanges(this.cdr);
|
|
2829
|
-
safeDetectChanges(this.parentCdr);
|
|
2830
|
-
safeDetectChanges(this.envCdr);
|
|
2831
|
-
}
|
|
2832
|
-
ngOnDestroy() {
|
|
2833
|
-
if (this.sub)
|
|
2834
|
-
this.sub.unsubscribe();
|
|
2835
|
-
this.latestValue = undefined;
|
|
2836
|
-
this.obj = undefined;
|
|
2837
|
-
}
|
|
2838
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPush, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
2839
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "16.0.0", ngImport: i0, type: NgtPush, isStandalone: true, name: "ngtPush", pure: false }); }
|
|
2840
|
-
}
|
|
2841
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPush, decorators: [{
|
|
2842
|
-
type: Pipe,
|
|
2843
|
-
args: [{ name: 'ngtPush', pure: false, standalone: true }]
|
|
2844
|
-
}] });
|
|
2845
|
-
|
|
2846
2763
|
const privateKeys = [
|
|
2847
2764
|
'get',
|
|
2848
2765
|
'set',
|
|
@@ -2855,20 +2772,23 @@ const privateKeys = [
|
|
|
2855
2772
|
'advance',
|
|
2856
2773
|
'size',
|
|
2857
2774
|
'viewport',
|
|
2858
|
-
'addInteraction',
|
|
2859
|
-
'removeInteraction',
|
|
2860
2775
|
];
|
|
2861
2776
|
class NgtPortalBeforeRender {
|
|
2777
|
+
#portalStore;
|
|
2778
|
+
#subscription;
|
|
2862
2779
|
constructor() {
|
|
2863
|
-
this
|
|
2780
|
+
this.#portalStore = inject(NgtStore);
|
|
2864
2781
|
this.renderPriority = 1;
|
|
2865
2782
|
this.beforeRender = new EventEmitter();
|
|
2783
|
+
inject(DestroyRef).onDestroy(() => {
|
|
2784
|
+
this.#subscription?.();
|
|
2785
|
+
});
|
|
2866
2786
|
}
|
|
2867
2787
|
ngOnInit() {
|
|
2868
2788
|
let oldClear;
|
|
2869
|
-
this
|
|
2870
|
-
this.beforeRender.emit({ ...this
|
|
2871
|
-
const { gl, scene, camera } = this
|
|
2789
|
+
this.#subscription = this.#portalStore.get('internal').subscribe(({ delta, frame }) => {
|
|
2790
|
+
this.beforeRender.emit({ ...this.#portalStore.get(), delta, frame });
|
|
2791
|
+
const { gl, scene, camera } = this.#portalStore.get();
|
|
2872
2792
|
oldClear = gl.autoClear;
|
|
2873
2793
|
if (this.renderPriority === 1) {
|
|
2874
2794
|
// clear scene and render with default
|
|
@@ -2881,10 +2801,7 @@ class NgtPortalBeforeRender {
|
|
|
2881
2801
|
gl.render(scene, camera);
|
|
2882
2802
|
// restore
|
|
2883
2803
|
gl.autoClear = oldClear;
|
|
2884
|
-
}, this.renderPriority, this
|
|
2885
|
-
}
|
|
2886
|
-
ngOnDestroy() {
|
|
2887
|
-
this.subscription?.();
|
|
2804
|
+
}, this.renderPriority, this.#portalStore);
|
|
2888
2805
|
}
|
|
2889
2806
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPortalBeforeRender, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2890
2807
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtPortalBeforeRender, isStandalone: true, selector: "[ngtPortalBeforeRender]", inputs: { renderPriority: "renderPriority", parentScene: "parentScene", parentCamera: "parentCamera" }, outputs: { beforeRender: "beforeRender" }, ngImport: i0 }); }
|
|
@@ -2892,21 +2809,23 @@ class NgtPortalBeforeRender {
|
|
|
2892
2809
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPortalBeforeRender, decorators: [{
|
|
2893
2810
|
type: Directive,
|
|
2894
2811
|
args: [{ selector: '[ngtPortalBeforeRender]', standalone: true }]
|
|
2895
|
-
}], propDecorators: { renderPriority: [{
|
|
2812
|
+
}], ctorParameters: function () { return []; }, propDecorators: { renderPriority: [{
|
|
2896
2813
|
type: Input
|
|
2897
2814
|
}], parentScene: [{
|
|
2898
|
-
type: Input
|
|
2815
|
+
type: Input,
|
|
2816
|
+
args: [{ required: true }]
|
|
2899
2817
|
}], parentCamera: [{
|
|
2900
|
-
type: Input
|
|
2818
|
+
type: Input,
|
|
2819
|
+
args: [{ required: true }]
|
|
2901
2820
|
}], beforeRender: [{
|
|
2902
2821
|
type: Output
|
|
2903
2822
|
}] } });
|
|
2904
2823
|
class NgtPortalContent {
|
|
2905
2824
|
constructor(vcr, parentVcr) {
|
|
2906
2825
|
const commentNode = vcr.element.nativeElement;
|
|
2907
|
-
if (commentNode[
|
|
2908
|
-
commentNode[
|
|
2909
|
-
delete commentNode[
|
|
2826
|
+
if (commentNode[SPECIAL_INTERNAL_ADD_COMMENT]) {
|
|
2827
|
+
commentNode[SPECIAL_INTERNAL_ADD_COMMENT](parentVcr.element.nativeElement);
|
|
2828
|
+
delete commentNode[SPECIAL_INTERNAL_ADD_COMMENT];
|
|
2910
2829
|
}
|
|
2911
2830
|
}
|
|
2912
2831
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPortalContent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ViewContainerRef, skipSelf: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
@@ -2918,32 +2837,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
|
|
|
2918
2837
|
}], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ViewContainerRef, decorators: [{
|
|
2919
2838
|
type: SkipSelf
|
|
2920
2839
|
}] }]; } });
|
|
2921
|
-
class NgtPortal extends
|
|
2922
|
-
constructor() {
|
|
2923
|
-
super(...arguments);
|
|
2924
|
-
this.autoRender = true;
|
|
2925
|
-
this.autoRenderPriority = 1;
|
|
2926
|
-
this.beforeRender = new EventEmitter();
|
|
2927
|
-
this.parentStore = inject(NgtStore, { skipSelf: true });
|
|
2928
|
-
this.parentScene = this.parentStore.get('scene');
|
|
2929
|
-
this.parentCamera = this.parentStore.get('camera');
|
|
2930
|
-
this.portalStore = inject(NgtStore, { self: true });
|
|
2931
|
-
this.raycaster = new THREE.Raycaster();
|
|
2932
|
-
this.pointer = new THREE.Vector2();
|
|
2933
|
-
this.portalContentRendered = false;
|
|
2934
|
-
}
|
|
2840
|
+
class NgtPortal extends NgtSignalStore {
|
|
2935
2841
|
set container(container) {
|
|
2936
2842
|
this.set({ container });
|
|
2937
2843
|
}
|
|
2938
2844
|
set state(state) {
|
|
2939
2845
|
this.set({ state });
|
|
2940
2846
|
}
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2847
|
+
#parentStore;
|
|
2848
|
+
#portalStore;
|
|
2849
|
+
#injector;
|
|
2850
|
+
#zone;
|
|
2851
|
+
#raycaster;
|
|
2852
|
+
#pointer;
|
|
2853
|
+
#portalContentView;
|
|
2854
|
+
constructor() {
|
|
2855
|
+
super({ container: injectNgtRef(prepare(new THREE.Scene())) });
|
|
2856
|
+
this.autoRender = true;
|
|
2857
|
+
this.autoRenderPriority = 1;
|
|
2858
|
+
this.beforeRender = new EventEmitter();
|
|
2859
|
+
this.#parentStore = inject(NgtStore, { skipSelf: true });
|
|
2860
|
+
this.parentScene = this.#parentStore.get('scene');
|
|
2861
|
+
this.parentCamera = this.#parentStore.get('camera');
|
|
2862
|
+
this.#portalStore = inject(NgtStore, { self: true });
|
|
2863
|
+
this.#injector = inject(Injector);
|
|
2864
|
+
this.#zone = inject(NgZone);
|
|
2865
|
+
this.#raycaster = new THREE.Raycaster();
|
|
2866
|
+
this.#pointer = new THREE.Vector2();
|
|
2867
|
+
this.portalContentRendered = false;
|
|
2868
|
+
inject(DestroyRef).onDestroy(() => {
|
|
2869
|
+
if (this.#portalContentView && !this.#portalContentView.destroyed) {
|
|
2870
|
+
this.#portalContentView.destroy();
|
|
2871
|
+
}
|
|
2872
|
+
});
|
|
2944
2873
|
}
|
|
2945
2874
|
ngOnInit() {
|
|
2946
|
-
const previousState = this
|
|
2875
|
+
const previousState = this.#parentStore.get();
|
|
2947
2876
|
const inputsState = this.get();
|
|
2948
2877
|
if (!inputsState.state && this.autoRender) {
|
|
2949
2878
|
inputsState.state = { events: { priority: this.autoRenderPriority + 1 } };
|
|
@@ -2953,43 +2882,42 @@ class NgtPortal extends NgtRxStore {
|
|
|
2953
2882
|
const container = is.ref(containerState) ? containerState.nativeElement : containerState;
|
|
2954
2883
|
const localState = getLocalState(container);
|
|
2955
2884
|
if (!localState.store) {
|
|
2956
|
-
localState.store = this
|
|
2885
|
+
localState.store = this.#portalStore;
|
|
2957
2886
|
}
|
|
2958
|
-
this
|
|
2887
|
+
this.#portalStore.set({
|
|
2959
2888
|
...previousState,
|
|
2960
2889
|
scene: container,
|
|
2961
|
-
raycaster: this
|
|
2962
|
-
pointer: this
|
|
2963
|
-
previousStore: this
|
|
2890
|
+
raycaster: this.#raycaster,
|
|
2891
|
+
pointer: this.#pointer,
|
|
2892
|
+
previousStore: this.#parentStore,
|
|
2964
2893
|
events: { ...previousState.events, ...(events || {}) },
|
|
2965
2894
|
size: { ...previousState.size, ...(size || {}) },
|
|
2966
2895
|
...restInputsState,
|
|
2967
|
-
get: this
|
|
2968
|
-
set: this
|
|
2969
|
-
|
|
2970
|
-
setEvents: (events) => this.portalStore.set((state) => ({ ...state, events: { ...state.events, ...events } })),
|
|
2896
|
+
get: this.#portalStore.get.bind(this.#portalStore),
|
|
2897
|
+
set: this.#portalStore.set.bind(this.#portalStore),
|
|
2898
|
+
setEvents: (events) => this.#portalStore.set((state) => ({ ...state, events: { ...state.events, ...events } })),
|
|
2971
2899
|
});
|
|
2972
|
-
|
|
2900
|
+
const parentState = this.#parentStore.select();
|
|
2901
|
+
effect(() => {
|
|
2902
|
+
const previous = parentState();
|
|
2903
|
+
this.#zone.runOutsideAngular(() => {
|
|
2904
|
+
this.#portalStore.set((state) => this.#inject(previous, state));
|
|
2905
|
+
});
|
|
2906
|
+
}, { injector: this.#injector, allowSignalWrites: true });
|
|
2973
2907
|
requestAnimationFrame(() => {
|
|
2974
|
-
this
|
|
2908
|
+
this.#portalStore.set((injectState) => this.#inject(this.#parentStore.get(), injectState));
|
|
2975
2909
|
});
|
|
2976
|
-
this
|
|
2977
|
-
this
|
|
2910
|
+
this.#portalContentView = this.portalContentAnchor.createEmbeddedView(this.portalContentTemplate);
|
|
2911
|
+
safeDetectChanges(this.#portalContentView);
|
|
2978
2912
|
this.portalContentRendered = true;
|
|
2979
2913
|
}
|
|
2980
2914
|
onBeforeRender(portal) {
|
|
2981
2915
|
this.beforeRender.emit({
|
|
2982
|
-
root: { ...this
|
|
2916
|
+
root: { ...this.#parentStore.get(), delta: portal.delta, frame: portal.frame },
|
|
2983
2917
|
portal,
|
|
2984
2918
|
});
|
|
2985
2919
|
}
|
|
2986
|
-
|
|
2987
|
-
if (this.portalContentView && !this.portalContentView.destroyed) {
|
|
2988
|
-
this.portalContentView.destroy();
|
|
2989
|
-
}
|
|
2990
|
-
super.ngOnDestroy();
|
|
2991
|
-
}
|
|
2992
|
-
inject(rootState, injectState) {
|
|
2920
|
+
#inject(rootState, injectState) {
|
|
2993
2921
|
const intersect = { ...rootState };
|
|
2994
2922
|
Object.keys(intersect).forEach((key) => {
|
|
2995
2923
|
if (privateKeys.includes(key) ||
|
|
@@ -3009,16 +2937,16 @@ class NgtPortal extends NgtRxStore {
|
|
|
3009
2937
|
return {
|
|
3010
2938
|
...intersect,
|
|
3011
2939
|
scene: is.ref(inputs.container) ? inputs.container.nativeElement : inputs.container,
|
|
3012
|
-
raycaster: this
|
|
3013
|
-
pointer: this
|
|
3014
|
-
previousStore: this
|
|
2940
|
+
raycaster: this.#raycaster,
|
|
2941
|
+
pointer: this.#pointer,
|
|
2942
|
+
previousStore: this.#parentStore,
|
|
3015
2943
|
events: { ...rootState.events, ...(injectState?.events || {}), ...events },
|
|
3016
2944
|
size: { ...rootState.size, ...size },
|
|
3017
2945
|
viewport: { ...rootState.viewport, ...(viewport || {}) },
|
|
3018
2946
|
...restInputsState,
|
|
3019
2947
|
};
|
|
3020
2948
|
}
|
|
3021
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPortal, deps:
|
|
2949
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPortal, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3022
2950
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.0", type: NgtPortal, isStandalone: true, selector: "ngt-portal", inputs: { container: "container", state: "state", autoRender: "autoRender", autoRenderPriority: "autoRenderPriority" }, outputs: { beforeRender: "beforeRender" }, providers: [NgtStore], queries: [{ propertyName: "portalContentTemplate", first: true, predicate: NgtPortalContent, descendants: true, read: TemplateRef, static: true }], viewQueries: [{ propertyName: "portalContentAnchor", first: true, predicate: ["portalContentAnchor"], descendants: true, read: ViewContainerRef, static: true }], usesInheritance: true, ngImport: i0, template: `
|
|
3023
2951
|
<ng-container #portalContentAnchor>
|
|
3024
2952
|
<ng-container
|
|
@@ -3052,7 +2980,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
|
|
|
3052
2980
|
imports: [NgIf, NgtPortalBeforeRender],
|
|
3053
2981
|
providers: [NgtStore],
|
|
3054
2982
|
}]
|
|
3055
|
-
}], propDecorators: { container: [{
|
|
2983
|
+
}], ctorParameters: function () { return []; }, propDecorators: { container: [{
|
|
3056
2984
|
type: Input
|
|
3057
2985
|
}], state: [{
|
|
3058
2986
|
type: Input
|
|
@@ -3070,15 +2998,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
|
|
|
3070
2998
|
args: ['portalContentAnchor', { read: ViewContainerRef, static: true }]
|
|
3071
2999
|
}] } });
|
|
3072
3000
|
|
|
3001
|
+
var _a;
|
|
3073
3002
|
class NgtRoutedScene {
|
|
3074
|
-
static {
|
|
3075
|
-
|
|
3076
|
-
|
|
3003
|
+
static { _a = ROUTED_SCENE; }
|
|
3004
|
+
static { this[_a] = true; }
|
|
3005
|
+
constructor(router, cdr) {
|
|
3077
3006
|
router.events
|
|
3078
|
-
.pipe(filter((event) => event instanceof ActivationEnd),
|
|
3007
|
+
.pipe(filter((event) => event instanceof ActivationEnd), takeUntilDestroyed())
|
|
3079
3008
|
.subscribe(() => safeDetectChanges(cdr));
|
|
3080
3009
|
}
|
|
3081
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRoutedScene, deps: [{ token: i1.Router }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3010
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRoutedScene, deps: [{ token: i1.Router }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3082
3011
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.0", type: NgtRoutedScene, isStandalone: true, selector: "ngt-routed-scene", ngImport: i0, template: `<router-outlet />`, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] }); }
|
|
3083
3012
|
}
|
|
3084
3013
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRoutedScene, decorators: [{
|
|
@@ -3089,11 +3018,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
|
|
|
3089
3018
|
template: `<router-outlet />`,
|
|
3090
3019
|
imports: [RouterOutlet],
|
|
3091
3020
|
}]
|
|
3092
|
-
}], ctorParameters: function () { return [{ type: i1.Router }]; } });
|
|
3021
|
+
}], ctorParameters: function () { return [{ type: i1.Router }, { type: i0.ChangeDetectorRef }]; } });
|
|
3093
3022
|
|
|
3094
3023
|
/**
|
|
3095
3024
|
* Generated bundle index. Do not edit.
|
|
3096
3025
|
*/
|
|
3097
3026
|
|
|
3098
|
-
export { NGT_CATALOGUE, NgtArgs, NgtCanvas, NgtParent, NgtPortal,
|
|
3027
|
+
export { NGT_CATALOGUE, NgtArgs, NgtCanvas, NgtParent, NgtPortal, NgtPortalContent, NgtRepeat, NgtRoutedScene, NgtSignalStore, NgtStore, addAfterEffect, addEffect, addTail, applyProps, checkNeedsUpdate, checkUpdate, createAttachFunction, extend, getLocalState, injectBeforeRender, injectNgtLoader, injectNgtRef, invalidateInstance, is, makeDefaultCamera, makeDefaultRenderer, makeDpr, makeId, makeObjectGraph, prepare, rootStateMap, safeDetectChanges, updateCamera };
|
|
3099
3028
|
//# sourceMappingURL=angular-three.mjs.map
|