angular-three 2.0.0-beta.6 → 2.0.0-beta.8
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 +4 -147
- package/esm2022/angular-three.mjs +1 -1
- package/esm2022/index.mjs +10 -9
- package/esm2022/lib/before-render.mjs +13 -0
- package/esm2022/lib/canvas.mjs +129 -161
- package/esm2022/lib/directives/args.mjs +13 -11
- package/esm2022/lib/directives/common.mjs +28 -27
- package/esm2022/lib/directives/key.mjs +29 -0
- package/esm2022/lib/directives/parent.mjs +13 -11
- package/esm2022/lib/directives/repeat.mjs +5 -6
- package/esm2022/lib/dom/events.mjs +6 -1
- package/esm2022/lib/events.mjs +75 -58
- package/esm2022/lib/instance.mjs +65 -0
- package/esm2022/lib/loader.mjs +17 -20
- package/esm2022/lib/loop.mjs +6 -3
- package/esm2022/lib/portal.mjs +103 -112
- package/esm2022/lib/ref.mjs +48 -0
- package/esm2022/lib/renderer/catalogue.mjs +7 -0
- package/esm2022/lib/renderer/constants.mjs +21 -0
- package/esm2022/lib/renderer/index.mjs +409 -0
- package/esm2022/lib/renderer/store.mjs +61 -38
- package/esm2022/lib/renderer/utils.mjs +20 -43
- package/esm2022/lib/roots.mjs +249 -0
- package/esm2022/lib/routed-scene.mjs +6 -7
- package/esm2022/lib/store.mjs +207 -0
- package/esm2022/lib/three-types.mjs +1 -1
- package/esm2022/lib/types.mjs +1 -1
- package/esm2022/lib/utils/apply-props.mjs +12 -7
- package/esm2022/lib/utils/assert-injection-context.mjs +14 -0
- package/esm2022/lib/utils/attach.mjs +2 -2
- package/esm2022/lib/utils/create-injection-token.mjs +47 -0
- package/esm2022/lib/utils/is.mjs +1 -1
- package/esm2022/lib/utils/make.mjs +1 -1
- package/esm2022/lib/utils/safe-detect-changes.mjs +15 -13
- package/esm2022/lib/utils/signal-store.mjs +91 -0
- package/esm2022/lib/utils/update.mjs +1 -1
- package/fesm2022/angular-three.mjs +1569 -1425
- package/fesm2022/angular-three.mjs.map +1 -1
- package/index.d.ts +10 -8
- package/lib/{di/before-render.d.ts → before-render.d.ts} +1 -1
- package/lib/canvas.d.ts +81 -11
- package/lib/directives/args.d.ts +2 -2
- package/lib/directives/common.d.ts +5 -1
- package/lib/directives/key.d.ts +10 -0
- package/lib/directives/parent.d.ts +5 -5
- package/lib/dom/events.d.ts +3 -2
- package/lib/events.d.ts +78 -2
- package/lib/instance.d.ts +36 -0
- package/lib/loader.d.ts +13 -2
- package/lib/loop.d.ts +64 -6
- package/lib/portal.d.ts +21 -12
- package/lib/{di/ref.d.ts → ref.d.ts} +3 -2
- package/lib/renderer/catalogue.d.ts +9 -0
- package/lib/renderer/constants.d.ts +20 -0
- package/lib/renderer/index.d.ts +5 -0
- package/lib/renderer/store.d.ts +21 -15
- package/lib/renderer/utils.d.ts +29 -19
- package/lib/roots.d.ts +11 -0
- package/lib/routed-scene.d.ts +1 -1
- package/lib/store.d.ts +143 -0
- package/lib/three-types.d.ts +5 -5
- package/lib/types.d.ts +1 -309
- package/lib/utils/apply-props.d.ts +4 -2
- package/lib/utils/attach.d.ts +4 -2
- package/lib/utils/create-injection-token.d.ts +27 -0
- package/lib/utils/is.d.ts +3 -2
- package/lib/utils/make.d.ts +12 -1
- package/lib/utils/safe-detect-changes.d.ts +2 -2
- package/lib/utils/signal-store.d.ts +17 -0
- package/lib/utils/update.d.ts +1 -1
- package/metadata.json +1 -0
- package/package.json +3 -3
- package/plugin/README.md +11 -0
- package/plugin/generators.json +39 -0
- package/plugin/package.json +6 -0
- package/plugin/src/generators/init/compat.d.ts +2 -0
- package/plugin/src/generators/init/compat.js +6 -0
- package/plugin/src/generators/init/compat.js.map +1 -0
- package/plugin/src/generators/init/generator.d.ts +2 -0
- package/plugin/src/generators/init/generator.js +48 -0
- package/plugin/src/generators/init/generator.js.map +1 -0
- package/plugin/src/generators/init/schema.json +6 -0
- package/plugin/src/generators/init-postprocessing/compat.d.ts +2 -0
- package/plugin/src/generators/init-postprocessing/compat.js +6 -0
- package/plugin/src/generators/init-postprocessing/compat.js.map +1 -0
- package/plugin/src/generators/init-postprocessing/generator.d.ts +2 -0
- package/plugin/src/generators/init-postprocessing/generator.js +20 -0
- package/plugin/src/generators/init-postprocessing/generator.js.map +1 -0
- package/plugin/src/generators/init-postprocessing/schema.json +6 -0
- package/plugin/src/generators/init-soba/compat.d.ts +2 -0
- package/plugin/src/generators/init-soba/compat.js +6 -0
- package/plugin/src/generators/init-soba/compat.js.map +1 -0
- package/plugin/src/generators/init-soba/generator.d.ts +2 -0
- package/plugin/src/generators/init-soba/generator.js +24 -0
- package/plugin/src/generators/init-soba/generator.js.map +1 -0
- package/plugin/src/generators/init-soba/schema.json +6 -0
- package/plugin/src/generators/versions.d.ts +9 -0
- package/plugin/src/generators/versions.js +13 -0
- package/plugin/src/generators/versions.js.map +1 -0
- package/plugin/src/index.d.ts +3 -0
- package/plugin/src/index.js +10 -0
- package/plugin/src/index.js.map +1 -0
- package/web-types.json +1 -0
- package/esm2022/lib/di/before-render.mjs +0 -13
- package/esm2022/lib/di/catalogue.mjs +0 -7
- package/esm2022/lib/di/ref.mjs +0 -54
- package/esm2022/lib/renderer/di.mjs +0 -3
- package/esm2022/lib/renderer/enums.mjs +0 -2
- package/esm2022/lib/renderer/provider.mjs +0 -18
- package/esm2022/lib/renderer/renderer.mjs +0 -367
- package/esm2022/lib/stores/signal.store.mjs +0 -78
- package/esm2022/lib/stores/store.mjs +0 -420
- package/esm2022/lib/utils/assert-in-injection-context.mjs +0 -14
- package/esm2022/lib/utils/instance.mjs +0 -66
- package/esm2022/lib/utils/timing.mjs +0 -9
- package/lib/di/catalogue.d.ts +0 -3
- package/lib/renderer/di.d.ts +0 -2
- package/lib/renderer/enums.d.ts +0 -26
- package/lib/renderer/provider.d.ts +0 -8
- package/lib/renderer/renderer.d.ts +0 -49
- package/lib/stores/signal.store.d.ts +0 -21
- package/lib/stores/store.d.ts +0 -13
- package/lib/utils/instance.d.ts +0 -4
- package/lib/utils/timing.d.ts +0 -2
- /package/lib/utils/{assert-in-injection-context.d.ts → assert-injection-context.d.ts} +0 -0
|
@@ -1,82 +1,97 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
import { provideNgxResizeOptions, NgxResize } from 'ngx-resize';
|
|
4
|
-
import * as THREE from 'three';
|
|
2
|
+
import { untracked, computed, signal, ElementRef, inject, Injector, assertInInjectionContext, runInInjectionContext, DestroyRef, effect, InjectionToken, ChangeDetectorRef, Optional, SkipSelf, ViewContainerRef, NgZone, TemplateRef, Directive, Input, EventEmitter, getDebugNode, RendererFactory2, Injectable, makeEnvironmentProviders, provideZoneChangeDetection, EnvironmentInjector, createEnvironmentInjector, Component, ChangeDetectionStrategy, Output, ViewChild, ContentChild } from '@angular/core';
|
|
5
3
|
import { DOCUMENT, NgForOf, NgIf } from '@angular/common';
|
|
4
|
+
import { Subject, filter } from 'rxjs';
|
|
5
|
+
import * as THREE from 'three';
|
|
6
|
+
import { provideNgxResizeOptions, NgxResize } from 'ngx-resize';
|
|
6
7
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
7
8
|
import * as i1 from '@angular/router';
|
|
8
9
|
import { ActivationEnd, RouterOutlet } from '@angular/router';
|
|
9
|
-
import { filter } from 'rxjs';
|
|
10
10
|
|
|
11
|
-
const STORE_COMPUTED_KEY = '
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
11
|
+
const STORE_COMPUTED_KEY = '__ngt_signal_store_computed__';
|
|
12
|
+
const setter = (_source) => (state) => {
|
|
13
|
+
const updater = (previous) => {
|
|
14
|
+
const partial = typeof state === 'function' ? state(previous) : state;
|
|
15
|
+
Object.keys(partial).forEach((key) => {
|
|
16
|
+
const typedKey = key;
|
|
17
|
+
if (partial[typedKey] === undefined && previous[typedKey] != null) {
|
|
18
|
+
partial[typedKey] = previous[typedKey];
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
return partial;
|
|
22
|
+
};
|
|
23
|
+
untracked(() => {
|
|
24
|
+
_source.update((previous) => ({ ...previous, ...updater(previous) }));
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
const patcher = (_source) => (state) => {
|
|
28
|
+
const updater = (previous) => {
|
|
29
|
+
Object.keys(state).forEach((key) => {
|
|
30
|
+
const typedKey = key;
|
|
31
|
+
if (state[typedKey] === undefined && previous[typedKey] != null) {
|
|
32
|
+
state[typedKey] = previous[typedKey];
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return state;
|
|
36
|
+
};
|
|
37
|
+
untracked(() => {
|
|
38
|
+
_source.update((previous) => ({ ...updater(previous), ...previous }));
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
const getter = (_source) => (...keys) => {
|
|
42
|
+
const root = untracked(_source);
|
|
43
|
+
if (keys.length === 0)
|
|
44
|
+
return root;
|
|
45
|
+
return keys.reduce((value, key) => value[key], root);
|
|
46
|
+
};
|
|
47
|
+
const selector = (_state, computedCache) => (...keysAndOptions) => {
|
|
48
|
+
if (keysAndOptions.length === 0)
|
|
49
|
+
return _state;
|
|
50
|
+
if (keysAndOptions.length === 1 && typeof keysAndOptions[0] === 'object') {
|
|
51
|
+
const cachedKey = STORE_COMPUTED_KEY.concat(JSON.stringify(keysAndOptions[0]));
|
|
52
|
+
if (!computedCache.has(cachedKey)) {
|
|
53
|
+
computedCache.set(cachedKey, computed(_state, keysAndOptions));
|
|
54
|
+
}
|
|
55
|
+
return computedCache.get(cachedKey);
|
|
56
|
+
}
|
|
57
|
+
const [keys, options] = parseStoreOptions(keysAndOptions);
|
|
58
|
+
const joinedKeys = keys.join('-');
|
|
59
|
+
const cachedKeys = joinedKeys.concat(options ? JSON.stringify(options) : '');
|
|
60
|
+
if (!computedCache.has(cachedKeys)) {
|
|
61
|
+
computedCache.set(cachedKeys, computed(() => keys.reduce((value, key) => value[key], _state()), options));
|
|
62
|
+
}
|
|
63
|
+
return computedCache.get(cachedKeys);
|
|
64
|
+
};
|
|
65
|
+
function signalStore(initialState = {}, options) {
|
|
66
|
+
let source;
|
|
67
|
+
let set;
|
|
68
|
+
let get;
|
|
69
|
+
let patch;
|
|
70
|
+
if (typeof initialState === 'function') {
|
|
71
|
+
source = signal({}, options);
|
|
72
|
+
get = getter(source);
|
|
73
|
+
set = setter(source);
|
|
74
|
+
patch = patcher(source);
|
|
75
|
+
source.set(initialState({ set, get, patch }));
|
|
67
76
|
}
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
else {
|
|
78
|
+
source = signal(initialState, options);
|
|
79
|
+
get = getter(source);
|
|
80
|
+
set = setter(source);
|
|
81
|
+
patch = patcher(source);
|
|
82
|
+
}
|
|
83
|
+
const state = source.asReadonly();
|
|
84
|
+
const computedCache = new Map();
|
|
85
|
+
const store = { select: selector(state, computedCache), get, set, patch, state };
|
|
86
|
+
// NOTE: internal _snapshot to debug current state
|
|
87
|
+
Object.defineProperty(store, '_snapshot', {
|
|
88
|
+
get: state,
|
|
89
|
+
configurable: false,
|
|
90
|
+
enumerable: false,
|
|
91
|
+
});
|
|
92
|
+
return store;
|
|
70
93
|
}
|
|
71
|
-
|
|
72
|
-
type: Injectable
|
|
73
|
-
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
|
74
|
-
type: Optional
|
|
75
|
-
}, {
|
|
76
|
-
type: Inject,
|
|
77
|
-
args: ['INITIAL_STATE']
|
|
78
|
-
}] }]; } });
|
|
79
|
-
function parseOptions(keysAndOptions) {
|
|
94
|
+
function parseStoreOptions(keysAndOptions) {
|
|
80
95
|
if (typeof keysAndOptions.at(-1) === 'object') {
|
|
81
96
|
return [keysAndOptions.slice(0, -1), keysAndOptions.at(-1)];
|
|
82
97
|
}
|
|
@@ -188,27 +203,26 @@ function prepare(object, localState) {
|
|
|
188
203
|
handlers: {},
|
|
189
204
|
objects,
|
|
190
205
|
nonObjects,
|
|
191
|
-
nativeProps:
|
|
206
|
+
nativeProps: signalStore(),
|
|
192
207
|
add: (object, type) => {
|
|
193
|
-
|
|
194
|
-
const current =
|
|
208
|
+
untracked(() => {
|
|
209
|
+
const current = instance.__ngt__[type]();
|
|
195
210
|
const foundIndex = current.indexOf((obj) => obj === object);
|
|
196
211
|
if (foundIndex > -1) {
|
|
197
212
|
// if we add an object with the same reference, then we switch it out
|
|
198
|
-
// and update the BehaviorSubject
|
|
199
213
|
current.splice(foundIndex, 1, object);
|
|
200
214
|
instance.__ngt__[type].set(current);
|
|
201
215
|
}
|
|
202
216
|
else {
|
|
203
217
|
instance.__ngt__[type].update((prev) => [...prev, object]);
|
|
204
218
|
}
|
|
205
|
-
notifyAncestors(
|
|
219
|
+
notifyAncestors(instance.__ngt__.parent());
|
|
206
220
|
});
|
|
207
221
|
},
|
|
208
222
|
remove: (object, type) => {
|
|
209
|
-
|
|
223
|
+
untracked(() => {
|
|
210
224
|
instance.__ngt__[type].update((prev) => prev.filter((o) => o !== object));
|
|
211
|
-
notifyAncestors(
|
|
225
|
+
notifyAncestors(instance.__ngt__.parent());
|
|
212
226
|
});
|
|
213
227
|
},
|
|
214
228
|
...rest,
|
|
@@ -224,7 +238,142 @@ function notifyAncestors(instance) {
|
|
|
224
238
|
localState.objects.update((prev) => prev);
|
|
225
239
|
if (localState.nonObjects)
|
|
226
240
|
localState.nonObjects.update((prev) => prev);
|
|
227
|
-
notifyAncestors(
|
|
241
|
+
notifyAncestors(localState.parent());
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// This function prepares a set of changes to be applied to the instance
|
|
245
|
+
function diffProps(instance, props) {
|
|
246
|
+
const propsEntries = Object.entries(props);
|
|
247
|
+
const changes = [];
|
|
248
|
+
for (const [propKey, propValue] of propsEntries) {
|
|
249
|
+
let key = propKey;
|
|
250
|
+
if (is.colorSpaceExist(instance)) {
|
|
251
|
+
if (propKey === 'encoding') {
|
|
252
|
+
key = 'colorSpace';
|
|
253
|
+
}
|
|
254
|
+
else if (propKey === 'outputEncoding') {
|
|
255
|
+
key = 'outputColorSpace';
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (is.equ(propValue, instance[key]))
|
|
259
|
+
continue;
|
|
260
|
+
changes.push([propKey, propValue]);
|
|
261
|
+
}
|
|
262
|
+
return changes;
|
|
263
|
+
}
|
|
264
|
+
// This function applies a set of changes to the instance
|
|
265
|
+
function applyProps(instance, props) {
|
|
266
|
+
// if props is empty
|
|
267
|
+
if (!Object.keys(props).length)
|
|
268
|
+
return instance;
|
|
269
|
+
// Filter equals, events and reserved props
|
|
270
|
+
// filter equals, events , and reserved props
|
|
271
|
+
const localState = getLocalState(instance);
|
|
272
|
+
const rootState = localState.store?.get();
|
|
273
|
+
const changes = diffProps(instance, props);
|
|
274
|
+
for (let i = 0; i < changes.length; i++) {
|
|
275
|
+
let [key, value] = changes[i];
|
|
276
|
+
// Alias (output)encoding => (output)colorSpace (since r152)
|
|
277
|
+
// https://github.com/pmndrs/react-three-fiber/pull/2829
|
|
278
|
+
if (is.colorSpaceExist(instance)) {
|
|
279
|
+
const sRGBEncoding = 3001;
|
|
280
|
+
const SRGBColorSpace = 'srgb';
|
|
281
|
+
const LinearSRGBColorSpace = 'srgb-linear';
|
|
282
|
+
if (key === 'encoding') {
|
|
283
|
+
key = 'colorSpace';
|
|
284
|
+
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
285
|
+
}
|
|
286
|
+
else if (key === 'outputEncoding') {
|
|
287
|
+
key = 'outputColorSpace';
|
|
288
|
+
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const currentInstance = instance;
|
|
292
|
+
const targetProp = currentInstance[key];
|
|
293
|
+
// special treatmen for objects with support for set/copy, and layers
|
|
294
|
+
if (targetProp && targetProp['set'] && (targetProp['copy'] || targetProp instanceof THREE.Layers)) {
|
|
295
|
+
const isColor = targetProp instanceof THREE.Color;
|
|
296
|
+
// if value is an array
|
|
297
|
+
if (Array.isArray(value)) {
|
|
298
|
+
if (targetProp['fromArray'])
|
|
299
|
+
targetProp['fromArray'](value);
|
|
300
|
+
else
|
|
301
|
+
targetProp['set'](...value);
|
|
302
|
+
}
|
|
303
|
+
// test again target.copy
|
|
304
|
+
else if (targetProp['copy'] &&
|
|
305
|
+
value &&
|
|
306
|
+
value.constructor &&
|
|
307
|
+
targetProp.constructor.name === value.constructor.name) {
|
|
308
|
+
targetProp['copy'](value);
|
|
309
|
+
if (!THREE.ColorManagement && !rootState.linear && isColor)
|
|
310
|
+
targetProp['convertSRGBToLinear']();
|
|
311
|
+
}
|
|
312
|
+
// if nothing else fits, just set the single value, ignore undefined
|
|
313
|
+
else if (value !== undefined) {
|
|
314
|
+
const isColor = targetProp instanceof THREE.Color;
|
|
315
|
+
// allow setting array scalars
|
|
316
|
+
if (!isColor && targetProp['setScalar'])
|
|
317
|
+
targetProp['setScalar'](value);
|
|
318
|
+
// layers have no copy function, copy the mask
|
|
319
|
+
else if (targetProp instanceof THREE.Layers && value instanceof THREE.Layers)
|
|
320
|
+
targetProp.mask = value.mask;
|
|
321
|
+
// otherwise just set ...
|
|
322
|
+
else
|
|
323
|
+
targetProp['set'](value);
|
|
324
|
+
// auto-convert srgb
|
|
325
|
+
if (!THREE.ColorManagement && !rootState?.linear && isColor)
|
|
326
|
+
targetProp.convertSRGBToLinear();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// else just overwrite the value
|
|
330
|
+
else {
|
|
331
|
+
currentInstance[key] = value;
|
|
332
|
+
// auto-convert srgb textures
|
|
333
|
+
if (currentInstance[key] instanceof THREE.Texture &&
|
|
334
|
+
currentInstance[key].format === THREE.RGBAFormat &&
|
|
335
|
+
currentInstance[key].type === THREE.UnsignedByteType) {
|
|
336
|
+
const texture = currentInstance[key];
|
|
337
|
+
if (rootState?.gl) {
|
|
338
|
+
if (is.colorSpaceExist(texture) && is.colorSpaceExist(rootState.gl))
|
|
339
|
+
texture.colorSpace = rootState.gl.outputColorSpace;
|
|
340
|
+
else
|
|
341
|
+
texture.encoding = rootState.gl.outputEncoding;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
checkUpdate(currentInstance[key]);
|
|
346
|
+
checkUpdate(targetProp);
|
|
347
|
+
invalidateInstance(instance);
|
|
348
|
+
}
|
|
349
|
+
const instanceHandlers = localState.eventCount;
|
|
350
|
+
const parent = localState.parent ? untracked(localState.parent) : null;
|
|
351
|
+
if (parent && rootState.internal && instance['raycast'] && instanceHandlers !== localState.eventCount) {
|
|
352
|
+
// Pre-emptively remove the instance from the interaction manager
|
|
353
|
+
const index = rootState.internal.interaction.indexOf(instance);
|
|
354
|
+
if (index > -1)
|
|
355
|
+
rootState.internal.interaction.splice(index, 1);
|
|
356
|
+
// Add the instance to the interaction manager only when it has handlers
|
|
357
|
+
if (localState.eventCount)
|
|
358
|
+
rootState.internal.interaction.push(instance);
|
|
359
|
+
}
|
|
360
|
+
if (parent && localState.afterUpdate && localState.afterUpdate.observed && changes.length) {
|
|
361
|
+
localState.afterUpdate.emit(instance);
|
|
362
|
+
}
|
|
363
|
+
return instance;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function assertInjectionContext(fn, injector) {
|
|
367
|
+
try {
|
|
368
|
+
if (!injector) {
|
|
369
|
+
return inject(Injector);
|
|
370
|
+
}
|
|
371
|
+
return injector;
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
!injector && assertInInjectionContext(fn);
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
228
377
|
}
|
|
229
378
|
|
|
230
379
|
const idCache = {};
|
|
@@ -276,97 +425,742 @@ function makeObjectGraph(object) {
|
|
|
276
425
|
return data;
|
|
277
426
|
}
|
|
278
427
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
428
|
+
const shallowLoose = { objects: 'shallow', strict: false };
|
|
429
|
+
const roots = new Map();
|
|
430
|
+
function injectCanvasRootInitializer(injector) {
|
|
431
|
+
injector = assertInjectionContext(injectCanvasRootInitializer, injector);
|
|
432
|
+
return runInInjectionContext(injector, () => {
|
|
433
|
+
const injectedStore = injectNgtStore();
|
|
434
|
+
const loop = injectNgtLoop();
|
|
435
|
+
const destroyRef = inject(DestroyRef);
|
|
436
|
+
return (canvas) => {
|
|
437
|
+
const exist = roots.has(canvas);
|
|
438
|
+
let store = roots.get(canvas);
|
|
439
|
+
if (store) {
|
|
440
|
+
console.warn('[NGT] Same canvas root is being created twice');
|
|
441
|
+
}
|
|
442
|
+
store ||= injectedStore;
|
|
443
|
+
if (!store) {
|
|
444
|
+
throw new Error('[NGT] No store initialized');
|
|
445
|
+
}
|
|
446
|
+
if (!exist) {
|
|
447
|
+
roots.set(canvas, store);
|
|
448
|
+
}
|
|
449
|
+
let isConfigured = false;
|
|
450
|
+
let invalidateRef;
|
|
451
|
+
destroyRef.onDestroy(() => invalidateRef?.destroy());
|
|
452
|
+
return {
|
|
453
|
+
isConfigured,
|
|
454
|
+
destroy: (timeout = 500) => {
|
|
455
|
+
const root = roots.get(canvas);
|
|
456
|
+
if (root) {
|
|
457
|
+
root.set((state) => ({ internal: { ...state.internal, active: false } }));
|
|
458
|
+
setTimeout(() => {
|
|
459
|
+
try {
|
|
460
|
+
const state = root.get();
|
|
461
|
+
state.events.disconnect?.();
|
|
462
|
+
state.gl?.renderLists?.dispose?.();
|
|
463
|
+
state.gl?.forceContextLoss?.();
|
|
464
|
+
if (state.gl?.xr)
|
|
465
|
+
state.xr.disconnect();
|
|
466
|
+
dispose(state);
|
|
467
|
+
roots.delete(canvas);
|
|
468
|
+
}
|
|
469
|
+
catch (e) {
|
|
470
|
+
console.error('[NGT] Unexpected error while destroying Canvas Root', e);
|
|
471
|
+
}
|
|
472
|
+
}, timeout);
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
configure: (inputs) => {
|
|
476
|
+
const { gl: glOptions, size: sizeOptions, camera: cameraOptions, raycaster: raycasterOptions, scene: sceneOptions, events, orthographic, lookAt, shadows, linear, legacy, flat, dpr, frameloop, performance, } = inputs;
|
|
477
|
+
const state = store.get();
|
|
478
|
+
const stateToUpdate = {};
|
|
479
|
+
// setup renderer
|
|
480
|
+
let gl = state.gl;
|
|
481
|
+
if (!state.gl)
|
|
482
|
+
stateToUpdate.gl = gl = makeDefaultRenderer(glOptions, canvas);
|
|
483
|
+
// setup raycaster
|
|
484
|
+
let raycaster = state.raycaster;
|
|
485
|
+
if (!raycaster)
|
|
486
|
+
stateToUpdate.raycaster = raycaster = new THREE.Raycaster();
|
|
487
|
+
// set raycaster options
|
|
488
|
+
const { params, ...options } = raycasterOptions || {};
|
|
489
|
+
if (!is.equ(options, raycaster, shallowLoose))
|
|
490
|
+
applyProps(raycaster, { ...options });
|
|
491
|
+
if (!is.equ(params, raycaster.params, shallowLoose)) {
|
|
492
|
+
applyProps(raycaster, { params: { ...raycaster.params, ...(params || {}) } });
|
|
493
|
+
}
|
|
494
|
+
// create default camera
|
|
495
|
+
if (!state.camera) {
|
|
496
|
+
const isCamera = is.camera(cameraOptions);
|
|
497
|
+
let camera = isCamera ? cameraOptions : makeDefaultCamera(orthographic || false, state.size);
|
|
498
|
+
if (!isCamera) {
|
|
499
|
+
if (cameraOptions)
|
|
500
|
+
applyProps(camera, cameraOptions);
|
|
501
|
+
// set position.z
|
|
502
|
+
if (!cameraOptions?.position)
|
|
503
|
+
camera.position.z = 5;
|
|
504
|
+
// always look at center or passed-in lookAt by default
|
|
505
|
+
if (!cameraOptions?.rotation && !cameraOptions?.quaternion) {
|
|
506
|
+
if (Array.isArray(lookAt))
|
|
507
|
+
camera.lookAt(lookAt[0], lookAt[1], lookAt[2]);
|
|
508
|
+
else if (lookAt instanceof THREE.Vector3)
|
|
509
|
+
camera.lookAt(lookAt);
|
|
510
|
+
else
|
|
511
|
+
camera.lookAt(0, 0, 0);
|
|
512
|
+
}
|
|
513
|
+
// update projection matrix after applyprops
|
|
514
|
+
camera.updateProjectionMatrix?.();
|
|
515
|
+
}
|
|
516
|
+
if (!is.instance(camera))
|
|
517
|
+
camera = prepare(camera, { store });
|
|
518
|
+
stateToUpdate.camera = camera;
|
|
519
|
+
}
|
|
520
|
+
// Set up scene (one time only!)
|
|
521
|
+
if (!state.scene) {
|
|
522
|
+
let scene;
|
|
523
|
+
if (sceneOptions instanceof THREE.Scene) {
|
|
524
|
+
scene = prepare(sceneOptions, { store });
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
scene = prepare(new THREE.Scene(), { store });
|
|
528
|
+
if (sceneOptions)
|
|
529
|
+
applyProps(scene, sceneOptions);
|
|
530
|
+
}
|
|
531
|
+
stateToUpdate.scene = scene;
|
|
532
|
+
}
|
|
533
|
+
// Set up XR (one time only!)
|
|
534
|
+
if (!state.xr) {
|
|
535
|
+
// Handle frame behavior in WebXR
|
|
536
|
+
const handleXRFrame = (timestamp, frame) => {
|
|
537
|
+
const state = store.get();
|
|
538
|
+
if (state.frameloop === 'never')
|
|
539
|
+
return;
|
|
540
|
+
loop.advance(timestamp, true, store, frame);
|
|
541
|
+
};
|
|
542
|
+
// Toggle render switching on session
|
|
543
|
+
const handleSessionChange = () => {
|
|
544
|
+
const state = store.get();
|
|
545
|
+
state.gl.xr.enabled = state.gl.xr.isPresenting;
|
|
546
|
+
state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
|
|
547
|
+
if (!state.gl.xr.isPresenting)
|
|
548
|
+
loop.invalidate(store);
|
|
549
|
+
};
|
|
550
|
+
// WebXR session manager
|
|
551
|
+
const xr = {
|
|
552
|
+
connect: () => {
|
|
553
|
+
gl.xr.addEventListener('sessionstart', handleSessionChange);
|
|
554
|
+
gl.xr.addEventListener('sessionend', handleSessionChange);
|
|
555
|
+
},
|
|
556
|
+
disconnect: () => {
|
|
557
|
+
gl.xr.removeEventListener('sessionstart', handleSessionChange);
|
|
558
|
+
gl.xr.removeEventListener('sessionend', handleSessionChange);
|
|
559
|
+
},
|
|
560
|
+
};
|
|
561
|
+
// Subscribe to WebXR session events
|
|
562
|
+
if (gl.xr && typeof gl.xr.addEventListener === 'function')
|
|
563
|
+
xr.connect();
|
|
564
|
+
stateToUpdate.xr = xr;
|
|
565
|
+
}
|
|
566
|
+
// Set shadowmap
|
|
567
|
+
if (gl.shadowMap) {
|
|
568
|
+
const oldEnabled = gl.shadowMap.enabled;
|
|
569
|
+
const oldType = gl.shadowMap.type;
|
|
570
|
+
gl.shadowMap.enabled = !!shadows;
|
|
571
|
+
if (typeof shadows === 'boolean') {
|
|
572
|
+
gl.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
573
|
+
}
|
|
574
|
+
else if (typeof shadows === 'string') {
|
|
575
|
+
const types = {
|
|
576
|
+
basic: THREE.BasicShadowMap,
|
|
577
|
+
percentage: THREE.PCFShadowMap,
|
|
578
|
+
soft: THREE.PCFSoftShadowMap,
|
|
579
|
+
variance: THREE.VSMShadowMap,
|
|
580
|
+
};
|
|
581
|
+
gl.shadowMap.type = types[shadows] ?? THREE.PCFSoftShadowMap;
|
|
582
|
+
}
|
|
583
|
+
else if (is.obj(shadows)) {
|
|
584
|
+
Object.assign(gl.shadowMap, shadows);
|
|
585
|
+
}
|
|
586
|
+
if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type)
|
|
587
|
+
checkNeedsUpdate(gl.shadowMap);
|
|
588
|
+
}
|
|
589
|
+
// Safely set color management if available.
|
|
590
|
+
// Avoid accessing THREE.ColorManagement to play nice with older versions
|
|
591
|
+
if (THREE.ColorManagement) {
|
|
592
|
+
const ColorManagement = THREE.ColorManagement;
|
|
593
|
+
if ('enabled' in ColorManagement)
|
|
594
|
+
ColorManagement['enabled'] = !legacy ?? false;
|
|
595
|
+
else if ('legacyMode' in ColorManagement)
|
|
596
|
+
ColorManagement['legacyMode'] = legacy ?? true;
|
|
597
|
+
}
|
|
598
|
+
// set color space and tonemapping preferences
|
|
599
|
+
const LinearEncoding = 3000;
|
|
600
|
+
const sRGBEncoding = 3001;
|
|
601
|
+
applyProps(gl, {
|
|
602
|
+
outputEncoding: linear ? LinearEncoding : sRGBEncoding,
|
|
603
|
+
toneMapping: flat ? THREE.NoToneMapping : THREE.ACESFilmicToneMapping,
|
|
604
|
+
});
|
|
605
|
+
// Update color management state
|
|
606
|
+
if (state.legacy !== legacy)
|
|
607
|
+
stateToUpdate.legacy = legacy;
|
|
608
|
+
if (state.linear !== linear)
|
|
609
|
+
stateToUpdate.linear = linear;
|
|
610
|
+
if (state.flat !== flat)
|
|
611
|
+
stateToUpdate.flat = flat;
|
|
612
|
+
// Set gl props
|
|
613
|
+
gl.setClearAlpha(0);
|
|
614
|
+
gl.setPixelRatio(makeDpr(state.viewport.dpr));
|
|
615
|
+
gl.setSize(state.size.width, state.size.height);
|
|
616
|
+
if (is.obj(glOptions) &&
|
|
617
|
+
!(typeof glOptions === 'function') &&
|
|
618
|
+
!is.renderer(glOptions) &&
|
|
619
|
+
!is.equ(glOptions, gl, shallowLoose)) {
|
|
620
|
+
applyProps(gl, glOptions);
|
|
621
|
+
}
|
|
622
|
+
// Store events internally
|
|
623
|
+
if (events && !state.events.handlers)
|
|
624
|
+
stateToUpdate.events = events(store);
|
|
625
|
+
// Check performance
|
|
626
|
+
if (performance && !is.equ(performance, state.performance, shallowLoose)) {
|
|
627
|
+
stateToUpdate.performance = { ...state.performance, ...performance };
|
|
628
|
+
}
|
|
629
|
+
store.set(stateToUpdate);
|
|
630
|
+
// Check size, allow it to take on container bounds initially
|
|
631
|
+
const size = computeInitialSize(canvas, sizeOptions);
|
|
632
|
+
if (!is.equ(size, state.size, shallowLoose)) {
|
|
633
|
+
state.setSize(size.width, size.height, size.top, size.left);
|
|
634
|
+
}
|
|
635
|
+
// Check pixelratio
|
|
636
|
+
if (dpr && state.viewport.dpr !== makeDpr(dpr))
|
|
637
|
+
state.setDpr(dpr);
|
|
638
|
+
// Check frameloop
|
|
639
|
+
if (state.frameloop !== frameloop)
|
|
640
|
+
state.setFrameloop(frameloop);
|
|
641
|
+
isConfigured = true;
|
|
642
|
+
invalidateRef?.destroy();
|
|
643
|
+
invalidateRef = effect(() => void store.state().invalidate(), { manualCleanup: true, injector });
|
|
644
|
+
},
|
|
645
|
+
};
|
|
646
|
+
};
|
|
303
647
|
});
|
|
304
|
-
if (store.get('previousStore')) {
|
|
305
|
-
removeInteractivity(store.get('previousStore'), object);
|
|
306
|
-
}
|
|
307
648
|
}
|
|
308
|
-
function
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const dy = event.offsetY - internal.initialClick[1];
|
|
314
|
-
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
649
|
+
function computeInitialSize(canvas, defaultSize) {
|
|
650
|
+
if (defaultSize)
|
|
651
|
+
return defaultSize;
|
|
652
|
+
if (canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
653
|
+
return canvas.parentElement.getBoundingClientRect();
|
|
315
654
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
655
|
+
return { width: 0, height: 0, top: 0, left: 0 };
|
|
656
|
+
}
|
|
657
|
+
// Disposes an object and all its properties
|
|
658
|
+
function dispose(obj) {
|
|
659
|
+
if (obj.dispose && obj.type !== 'Scene')
|
|
660
|
+
obj.dispose();
|
|
661
|
+
for (const p in obj) {
|
|
662
|
+
p.dispose?.();
|
|
663
|
+
delete obj[p];
|
|
322
664
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
instanceState.raycaster.camera = undefined;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
if (!state.previousStore) {
|
|
337
|
-
// make sure root-level pointer and ray are setup
|
|
338
|
-
state.events.compute?.(event, store);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function createInjectFn(token) {
|
|
668
|
+
return (injectOptions) => inject(token, injectOptions);
|
|
669
|
+
}
|
|
670
|
+
function createProvideFn(token, factory, deps, extraProviders) {
|
|
671
|
+
return (value) => {
|
|
672
|
+
let provider;
|
|
673
|
+
if (value) {
|
|
674
|
+
provider = { provide: token, useValue: value };
|
|
339
675
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
const objStore = objLocalState.store;
|
|
343
|
-
const objState = objStore?.get();
|
|
344
|
-
// skip event handling when noEvents is set, or when raycaster camera is null
|
|
345
|
-
if (!objState || !objState.events.enabled || objState.raycaster.camera === null)
|
|
346
|
-
return [];
|
|
347
|
-
// when the camera is undefined, we have to call the events layers to update function
|
|
348
|
-
if (objState.raycaster.camera === undefined) {
|
|
349
|
-
objState.events.compute?.(event, objStore, objState.previousStore);
|
|
350
|
-
// if the camera is still undefined, we have to skip this layer entirely
|
|
351
|
-
if (objState.raycaster.camera === undefined)
|
|
352
|
-
objState.raycaster.camera = null;
|
|
353
|
-
}
|
|
354
|
-
// intersect object by object
|
|
355
|
-
return objState.raycaster.camera ? objState.raycaster.intersectObject(obj, true) : [];
|
|
676
|
+
else {
|
|
677
|
+
provider = { provide: token, useFactory: factory, deps: (deps ?? []) };
|
|
356
678
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
679
|
+
return extraProviders ? [extraProviders, provider] : provider;
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
function createInjectionToken(factory, options) {
|
|
683
|
+
const opts = options ?? { isRoot: true };
|
|
684
|
+
opts.isRoot ??= true;
|
|
685
|
+
if (opts.isRoot) {
|
|
686
|
+
if (opts.token) {
|
|
687
|
+
throw new Error(`\
|
|
688
|
+
createInjectionToken is creating a root InjectionToken but an external token is passed in.
|
|
689
|
+
`);
|
|
690
|
+
}
|
|
691
|
+
const token = new InjectionToken(`Token for ${factory.name}`, {
|
|
692
|
+
factory: () => {
|
|
693
|
+
if (opts.deps && Array.isArray(opts.deps)) {
|
|
694
|
+
return factory(...opts.deps.map((dep) => inject(dep)));
|
|
695
|
+
}
|
|
696
|
+
return factory();
|
|
697
|
+
},
|
|
698
|
+
});
|
|
699
|
+
return [
|
|
700
|
+
createInjectFn(token),
|
|
701
|
+
createProvideFn(token, factory, opts.deps),
|
|
702
|
+
token,
|
|
703
|
+
];
|
|
704
|
+
}
|
|
705
|
+
const token = opts.token || new InjectionToken(`Token for ${factory.name}`);
|
|
706
|
+
return [
|
|
707
|
+
createInjectFn(token),
|
|
708
|
+
createProvideFn(token, factory, opts.deps, opts.extraProviders),
|
|
709
|
+
token,
|
|
710
|
+
];
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
function createSubs(callback, subs) {
|
|
714
|
+
const sub = { callback };
|
|
715
|
+
subs.add(sub);
|
|
716
|
+
return () => void subs.delete(sub);
|
|
717
|
+
}
|
|
718
|
+
const globalEffects = new Set();
|
|
719
|
+
const globalAfterEffects = new Set();
|
|
720
|
+
const globalTailEffects = new Set();
|
|
721
|
+
/**
|
|
722
|
+
* Adds a global render callback which is called each frame.
|
|
723
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addEffect
|
|
724
|
+
*/
|
|
725
|
+
const addEffect = (callback) => createSubs(callback, globalEffects);
|
|
726
|
+
/**
|
|
727
|
+
* Adds a global after-render callback which is called each frame.
|
|
728
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addAfterEffect
|
|
729
|
+
*/
|
|
730
|
+
const addAfterEffect = (callback) => createSubs(callback, globalAfterEffects);
|
|
731
|
+
/**
|
|
732
|
+
* Adds a global callback which is called when rendering stops.
|
|
733
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addTail
|
|
734
|
+
*/
|
|
735
|
+
const addTail = (callback) => createSubs(callback, globalTailEffects);
|
|
736
|
+
function run(effects, timestamp) {
|
|
737
|
+
if (!effects.size)
|
|
738
|
+
return;
|
|
739
|
+
for (const { callback } of effects.values()) {
|
|
740
|
+
callback(timestamp);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
function flushGlobalEffects(type, timestamp) {
|
|
744
|
+
switch (type) {
|
|
745
|
+
case 'before':
|
|
746
|
+
return run(globalEffects, timestamp);
|
|
747
|
+
case 'after':
|
|
748
|
+
return run(globalAfterEffects, timestamp);
|
|
749
|
+
case 'tail':
|
|
750
|
+
return run(globalTailEffects, timestamp);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
function render(timestamp, store, frame) {
|
|
754
|
+
const state = store.get();
|
|
755
|
+
// Run local effects
|
|
756
|
+
let delta = state.clock.getDelta();
|
|
757
|
+
// In frameloop='never' mode, clock times are updated using the provided timestamp
|
|
758
|
+
if (state.frameloop === 'never' && typeof timestamp === 'number') {
|
|
759
|
+
delta = timestamp - state.clock.elapsedTime;
|
|
760
|
+
state.clock.oldTime = state.clock.elapsedTime;
|
|
761
|
+
state.clock.elapsedTime = timestamp;
|
|
762
|
+
}
|
|
763
|
+
// Call subscribers (useFrame)
|
|
764
|
+
const subscribers = state.internal.subscribers;
|
|
765
|
+
for (let i = 0; i < subscribers.length; i++) {
|
|
766
|
+
const subscription = subscribers[i];
|
|
767
|
+
subscription.callback({ ...subscription.store.get(), delta, frame });
|
|
768
|
+
}
|
|
769
|
+
// Render content
|
|
770
|
+
if (!state.internal.priority && state.gl.render)
|
|
771
|
+
state.gl.render(state.scene, state.camera);
|
|
772
|
+
// Decrease frame count
|
|
773
|
+
state.internal.frames = Math.max(0, state.internal.frames - 1);
|
|
774
|
+
return state.frameloop === 'always' ? 1 : state.internal.frames;
|
|
775
|
+
}
|
|
776
|
+
function createLoop(roots) {
|
|
777
|
+
let running = false;
|
|
778
|
+
let repeat;
|
|
779
|
+
let frame;
|
|
780
|
+
function loop(timestamp) {
|
|
781
|
+
frame = requestAnimationFrame(loop);
|
|
782
|
+
running = true;
|
|
783
|
+
repeat = 0;
|
|
784
|
+
// Run effects
|
|
785
|
+
flushGlobalEffects('before', timestamp);
|
|
786
|
+
// Render all roots
|
|
787
|
+
for (const root of roots.values()) {
|
|
788
|
+
const state = root.get();
|
|
789
|
+
// If the frameloop is invalidated, do not run another frame
|
|
790
|
+
if (state.internal.active &&
|
|
791
|
+
(state.frameloop === 'always' || state.internal.frames > 0) &&
|
|
792
|
+
!state.gl.xr?.isPresenting) {
|
|
793
|
+
repeat += render(timestamp, root);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
// Run after-effects
|
|
797
|
+
flushGlobalEffects('after', timestamp);
|
|
798
|
+
// Stop the loop if nothing invalidates it
|
|
799
|
+
if (repeat === 0) {
|
|
800
|
+
// Tail call effects, they are called when rendering stops
|
|
801
|
+
flushGlobalEffects('tail', timestamp);
|
|
802
|
+
// Flag end of operation
|
|
803
|
+
running = false;
|
|
804
|
+
return cancelAnimationFrame(frame);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
function invalidate(store, frames = 1) {
|
|
808
|
+
const state = store?.get();
|
|
809
|
+
if (!state)
|
|
810
|
+
return roots.forEach((root) => invalidate(root, frames));
|
|
811
|
+
if (state.gl.xr?.isPresenting || !state.internal.active || state.frameloop === 'never')
|
|
812
|
+
return;
|
|
813
|
+
// Increase frames, do not go higher than 60
|
|
814
|
+
state.internal.frames = Math.min(60, state.internal.frames + frames);
|
|
815
|
+
// If the render-loop isn't active, start it
|
|
816
|
+
if (!running) {
|
|
817
|
+
running = true;
|
|
818
|
+
requestAnimationFrame(loop);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
function advance(timestamp, runGlobalEffects = true, store, frame) {
|
|
822
|
+
if (runGlobalEffects)
|
|
823
|
+
flushGlobalEffects('before', timestamp);
|
|
824
|
+
const state = store?.get();
|
|
825
|
+
if (!state)
|
|
826
|
+
for (const root of roots.values())
|
|
827
|
+
render(timestamp, root);
|
|
828
|
+
else
|
|
829
|
+
render(timestamp, store, frame);
|
|
830
|
+
if (runGlobalEffects)
|
|
831
|
+
flushGlobalEffects('after', timestamp);
|
|
832
|
+
}
|
|
833
|
+
return {
|
|
834
|
+
loop,
|
|
835
|
+
/**
|
|
836
|
+
* Invalidates the view, requesting a frame to be rendered. Will globally invalidate unless passed a root's state.
|
|
837
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#invalidate
|
|
838
|
+
*/
|
|
839
|
+
invalidate,
|
|
840
|
+
/**
|
|
841
|
+
* Advances the frameloop and runs render effects, useful for when manually rendering via `frameloop="never"`.
|
|
842
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#advance
|
|
843
|
+
*/
|
|
844
|
+
advance,
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
const [injectNgtLoop, , NGT_LOOP] = createInjectionToken(() => createLoop(roots));
|
|
848
|
+
|
|
849
|
+
function safeDetectChanges(...cdrs) {
|
|
850
|
+
cdrs.forEach((cdr) => {
|
|
851
|
+
if (!cdr)
|
|
852
|
+
return;
|
|
853
|
+
try {
|
|
854
|
+
// dynamic created component with ViewContainerRef#createComponent does not have Context
|
|
855
|
+
// but it has _attachedToViewContainer
|
|
856
|
+
if (cdr['_attachedToViewContainer'] || !!cdr['context']) {
|
|
857
|
+
cdr.detectChanges();
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
catch (e) {
|
|
861
|
+
cdr.markForCheck();
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
function storeFactory(loop, document, injector, parent) {
|
|
867
|
+
return runInInjectionContext(injector, () => {
|
|
868
|
+
const window = document.defaultView;
|
|
869
|
+
if (!window) {
|
|
870
|
+
// TODO: revisit this when we need to support multiple platforms
|
|
871
|
+
throw new Error(`[NGT] Window is not available.`);
|
|
872
|
+
}
|
|
873
|
+
const cdr = inject(ChangeDetectorRef);
|
|
874
|
+
// NOTE: using Subject because we do not care about late-subscribers
|
|
875
|
+
const pointerMissed$ = new Subject();
|
|
876
|
+
const store = signalStore(({ get, set }) => {
|
|
877
|
+
const { invalidate, advance } = loop;
|
|
878
|
+
const position = new THREE.Vector3();
|
|
879
|
+
const defaultTarget = new THREE.Vector3();
|
|
880
|
+
const tempTarget = new THREE.Vector3();
|
|
881
|
+
function getCurrentViewport(camera = get('camera'), target = defaultTarget, size = get('size')) {
|
|
882
|
+
const { width, height, top, left } = size;
|
|
883
|
+
const aspect = width / height;
|
|
884
|
+
if (target instanceof THREE.Vector3)
|
|
885
|
+
tempTarget.copy(target);
|
|
886
|
+
else
|
|
887
|
+
tempTarget.set(...target);
|
|
888
|
+
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
889
|
+
if (is.orthographicCamera(camera)) {
|
|
890
|
+
return {
|
|
891
|
+
width: width / camera.zoom,
|
|
892
|
+
height: height / camera.zoom,
|
|
893
|
+
top,
|
|
894
|
+
left,
|
|
895
|
+
factor: 1,
|
|
896
|
+
distance,
|
|
897
|
+
aspect,
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
const fov = (camera.fov * Math.PI) / 180; // convert vertical fov to radians
|
|
902
|
+
const h = 2 * Math.tan(fov / 2) * distance; // visible height
|
|
903
|
+
const w = h * (width / height);
|
|
904
|
+
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
let performanceTimeout = undefined;
|
|
908
|
+
const setPerformanceCurrent = (current) => set((state) => ({ performance: { ...state.performance, current } }));
|
|
909
|
+
const pointer = new THREE.Vector2();
|
|
910
|
+
return {
|
|
911
|
+
pointerMissed$: pointerMissed$.asObservable(),
|
|
912
|
+
events: { priority: 1, enabled: true, connected: false },
|
|
913
|
+
invalidate: (frames = 1) => invalidate(store, frames),
|
|
914
|
+
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, store),
|
|
915
|
+
legacy: false,
|
|
916
|
+
linear: false,
|
|
917
|
+
flat: false,
|
|
918
|
+
controls: null,
|
|
919
|
+
clock: new THREE.Clock(),
|
|
920
|
+
pointer,
|
|
921
|
+
frameloop: 'always',
|
|
922
|
+
performance: {
|
|
923
|
+
current: 1,
|
|
924
|
+
min: 0.5,
|
|
925
|
+
max: 1,
|
|
926
|
+
debounce: 200,
|
|
927
|
+
regress: () => {
|
|
928
|
+
const state = get();
|
|
929
|
+
// Clear timeout
|
|
930
|
+
if (performanceTimeout)
|
|
931
|
+
clearTimeout(performanceTimeout);
|
|
932
|
+
// Set lower bound performance
|
|
933
|
+
if (state.performance.current !== state.performance.min)
|
|
934
|
+
setPerformanceCurrent(state.performance.min);
|
|
935
|
+
// Go back to upper bound performance after a while unless something regresses meanwhile
|
|
936
|
+
performanceTimeout = setTimeout(() => {
|
|
937
|
+
setPerformanceCurrent(get('performance', 'max'));
|
|
938
|
+
safeDetectChanges(cdr);
|
|
939
|
+
}, state.performance.debounce);
|
|
940
|
+
},
|
|
941
|
+
},
|
|
942
|
+
size: { width: 0, height: 0, top: 0, left: 0, updateStyle: false },
|
|
943
|
+
viewport: {
|
|
944
|
+
initialDpr: 0,
|
|
945
|
+
dpr: 0,
|
|
946
|
+
width: 0,
|
|
947
|
+
height: 0,
|
|
948
|
+
top: 0,
|
|
949
|
+
left: 0,
|
|
950
|
+
aspect: 0,
|
|
951
|
+
distance: 0,
|
|
952
|
+
factor: 0,
|
|
953
|
+
getCurrentViewport,
|
|
954
|
+
},
|
|
955
|
+
setEvents: (events) => set((state) => ({ ...state, events: { ...state.events, ...events } })),
|
|
956
|
+
setSize: (width, height, top, left) => {
|
|
957
|
+
const camera = get('camera');
|
|
958
|
+
const size = { width, height, top: top || 0, left: left || 0 };
|
|
959
|
+
set((state) => ({
|
|
960
|
+
size,
|
|
961
|
+
viewport: { ...state.viewport, ...getCurrentViewport(camera, defaultTarget, size) },
|
|
962
|
+
}));
|
|
963
|
+
},
|
|
964
|
+
setDpr: (dpr) => set((state) => {
|
|
965
|
+
const resolved = makeDpr(dpr, window);
|
|
966
|
+
return {
|
|
967
|
+
viewport: {
|
|
968
|
+
...state.viewport,
|
|
969
|
+
dpr: resolved,
|
|
970
|
+
initialDpr: state.viewport.initialDpr || resolved,
|
|
971
|
+
},
|
|
972
|
+
};
|
|
973
|
+
}),
|
|
974
|
+
setFrameloop: (frameloop = 'always') => {
|
|
975
|
+
const clock = get('clock');
|
|
976
|
+
// if frameloop === "never" clock.elapsedTime is updated using advance(timestamp)
|
|
977
|
+
clock.stop();
|
|
978
|
+
clock.elapsedTime = 0;
|
|
979
|
+
if (frameloop !== 'never') {
|
|
980
|
+
clock.start();
|
|
981
|
+
clock.elapsedTime = 0;
|
|
982
|
+
}
|
|
983
|
+
set(() => ({ frameloop }));
|
|
984
|
+
},
|
|
985
|
+
previousRoot: parent,
|
|
986
|
+
internal: {
|
|
987
|
+
active: false,
|
|
988
|
+
priority: 0,
|
|
989
|
+
frames: 0,
|
|
990
|
+
lastEvent: new ElementRef(null),
|
|
991
|
+
interaction: [],
|
|
992
|
+
hovered: new Map(),
|
|
993
|
+
subscribers: [],
|
|
994
|
+
initialClick: [0, 0],
|
|
995
|
+
initialHits: [],
|
|
996
|
+
capturedMap: new Map(),
|
|
997
|
+
subscribe: (callback, priority = 0, _store = store) => {
|
|
998
|
+
const internal = get('internal');
|
|
999
|
+
// If this subscription was given a priority, it takes rendering into its own hands
|
|
1000
|
+
// For that reason we switch off automatic rendering and increase the manual flag
|
|
1001
|
+
// As long as this flag is positive there can be no internal rendering at all
|
|
1002
|
+
// because there could be multiple render subscriptions
|
|
1003
|
+
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1004
|
+
internal.subscribers.push({ callback, priority, store });
|
|
1005
|
+
// Register subscriber and sort layers from lowest to highest, meaning,
|
|
1006
|
+
// highest priority renders last (on top of the other frames)
|
|
1007
|
+
internal.subscribers = internal.subscribers.sort((a, b) => (a.priority || 0) - (b.priority || 0));
|
|
1008
|
+
return () => {
|
|
1009
|
+
const internal = get('internal');
|
|
1010
|
+
if (internal?.subscribers) {
|
|
1011
|
+
// Decrease manual flag if this subscription had a priority
|
|
1012
|
+
internal.priority = internal.priority - (priority > 0 ? 1 : 0);
|
|
1013
|
+
// Remove subscriber from list
|
|
1014
|
+
internal.subscribers = internal.subscribers.filter((s) => s.callback !== callback);
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
},
|
|
1018
|
+
},
|
|
1019
|
+
};
|
|
1020
|
+
});
|
|
1021
|
+
// NOTE: assign pointerMissed$ so we can use it in events
|
|
1022
|
+
Object.defineProperty(store, 'pointerMissed$', { get: () => pointerMissed$ });
|
|
1023
|
+
const state = store.get();
|
|
1024
|
+
let oldSize = state.size;
|
|
1025
|
+
let oldDpr = state.viewport.dpr;
|
|
1026
|
+
let oldCamera = state.camera;
|
|
1027
|
+
const _camera = store.select('camera');
|
|
1028
|
+
const _size = store.select('size');
|
|
1029
|
+
const _viewport = store.select('viewport');
|
|
1030
|
+
effect(() => {
|
|
1031
|
+
const [camera, size, viewport, gl] = [_camera(), _size(), _viewport(), store.get('gl')];
|
|
1032
|
+
// Resize camera and renderer on changes to size and pixelratio
|
|
1033
|
+
if (size !== oldSize || viewport.dpr !== oldDpr) {
|
|
1034
|
+
oldSize = size;
|
|
1035
|
+
oldDpr = viewport.dpr;
|
|
1036
|
+
// Update camera & renderer
|
|
1037
|
+
updateCamera(camera, size);
|
|
1038
|
+
gl.setPixelRatio(viewport.dpr);
|
|
1039
|
+
const updateStyle = typeof HTMLCanvasElement !== 'undefined' && gl.domElement instanceof HTMLCanvasElement;
|
|
1040
|
+
gl.setSize(size.width, size.height, updateStyle);
|
|
1041
|
+
}
|
|
1042
|
+
// Update viewport once the camera changes
|
|
1043
|
+
if (camera !== oldCamera) {
|
|
1044
|
+
oldCamera = camera;
|
|
1045
|
+
updateCamera(camera, size);
|
|
1046
|
+
// Update viewport
|
|
1047
|
+
store.set((state) => ({
|
|
1048
|
+
viewport: { ...state.viewport, ...state.viewport.getCurrentViewport(camera) },
|
|
1049
|
+
}));
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
return store;
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
const NGT_STORE = new InjectionToken('NgtStore token');
|
|
1056
|
+
const [injectNgtStore, provideNgtStore] = createInjectionToken(storeFactory, {
|
|
1057
|
+
isRoot: false,
|
|
1058
|
+
deps: [NGT_LOOP, DOCUMENT, Injector, [new Optional(), new SkipSelf(), NGT_STORE]],
|
|
1059
|
+
token: NGT_STORE,
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
function injectBeforeRender(cb, { priority = 0, injector } = {}) {
|
|
1063
|
+
injector = assertInjectionContext(injectBeforeRender, injector);
|
|
1064
|
+
return runInInjectionContext(injector, () => {
|
|
1065
|
+
const store = injectNgtStore();
|
|
1066
|
+
const sub = store.get('internal').subscribe(cb, priority, store);
|
|
1067
|
+
inject(DestroyRef).onDestroy(() => void sub());
|
|
1068
|
+
return sub;
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* Release pointer captures.
|
|
1074
|
+
* This is called by releasePointerCapture in the API, and when an object is removed.
|
|
1075
|
+
*/
|
|
1076
|
+
function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
|
|
1077
|
+
const captureData = captures.get(obj);
|
|
1078
|
+
if (captureData) {
|
|
1079
|
+
captures.delete(obj);
|
|
1080
|
+
// If this was the last capturing object for this pointer
|
|
1081
|
+
if (captures.size === 0) {
|
|
1082
|
+
capturedMap.delete(pointerId);
|
|
1083
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
function removeInteractivity(store, object) {
|
|
1088
|
+
const { internal } = store.get();
|
|
1089
|
+
// Removes every trace of an object from the data store
|
|
1090
|
+
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
1091
|
+
internal.initialHits = internal.initialHits.filter((o) => o !== object);
|
|
1092
|
+
internal.hovered.forEach((value, key) => {
|
|
1093
|
+
if (value.eventObject === object || value.object === object) {
|
|
1094
|
+
// Clear out intersects, they are outdated by now
|
|
1095
|
+
internal.hovered.delete(key);
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
internal.capturedMap.forEach((captures, pointerId) => {
|
|
1099
|
+
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
function createEvents(store) {
|
|
1103
|
+
/** Calculates delta */
|
|
1104
|
+
function calculateDistance(event) {
|
|
1105
|
+
const internal = store.get('internal');
|
|
1106
|
+
const dx = event.offsetX - internal.initialClick[0];
|
|
1107
|
+
const dy = event.offsetY - internal.initialClick[1];
|
|
1108
|
+
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
1109
|
+
}
|
|
1110
|
+
/** Returns true if an instance has a valid pointer-event registered, this excludes scroll, clicks etc */
|
|
1111
|
+
function filterPointerEvents(objects) {
|
|
1112
|
+
return objects.filter((obj) => ['move', 'over', 'enter', 'out', 'leave'].some((name) => {
|
|
1113
|
+
const eventName = `pointer${name}`;
|
|
1114
|
+
return getLocalState(obj).handlers?.[eventName];
|
|
1115
|
+
}));
|
|
1116
|
+
}
|
|
1117
|
+
function intersect(event, filter) {
|
|
1118
|
+
const state = store.get();
|
|
1119
|
+
const duplicates = new Set();
|
|
1120
|
+
const intersections = [];
|
|
1121
|
+
// Allow callers to eliminate event objects
|
|
1122
|
+
const eventsObjects = filter ? filter(state.internal.interaction) : state.internal.interaction;
|
|
1123
|
+
// Reset all raycaster cameras to undefined
|
|
1124
|
+
for (let i = 0; i < eventsObjects.length; i++) {
|
|
1125
|
+
const state = getLocalState(eventsObjects[i]).store.get();
|
|
1126
|
+
if (state) {
|
|
1127
|
+
state.raycaster.camera = undefined;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
if (!state.previousRoot) {
|
|
1131
|
+
// Make sure root-level pointer and ray are set up
|
|
1132
|
+
state.events.compute?.(event, store, null);
|
|
1133
|
+
}
|
|
1134
|
+
function handleRaycast(obj) {
|
|
1135
|
+
const objLocalState = getLocalState(obj);
|
|
1136
|
+
const objStore = objLocalState.store;
|
|
1137
|
+
const objState = objStore?.get();
|
|
1138
|
+
// Skip event handling when noEvents is set, or when the raycasters camera is null
|
|
1139
|
+
if (!objState || !objState.events.enabled || objState.raycaster.camera === null)
|
|
1140
|
+
return [];
|
|
1141
|
+
// When the camera is undefined we have to call the event layers update function
|
|
1142
|
+
if (objState.raycaster.camera === undefined) {
|
|
1143
|
+
objState.events.compute?.(event, objStore, objState.previousRoot);
|
|
1144
|
+
// If the camera is still undefined we have to skip this layer entirely
|
|
1145
|
+
if (objState.raycaster.camera === undefined)
|
|
1146
|
+
objState.raycaster.camera = null;
|
|
1147
|
+
}
|
|
1148
|
+
// Intersect object by object
|
|
1149
|
+
return objState.raycaster.camera ? objState.raycaster.intersectObject(obj, true) : [];
|
|
1150
|
+
}
|
|
1151
|
+
// Collect events
|
|
1152
|
+
let hits = eventsObjects
|
|
1153
|
+
// Intersect objects
|
|
1154
|
+
.flatMap(handleRaycast)
|
|
1155
|
+
// Sort by event priority and distance
|
|
1156
|
+
.sort((a, b) => {
|
|
1157
|
+
const aState = getLocalState(a.object).store.get();
|
|
1158
|
+
const bState = getLocalState(b.object).store.get();
|
|
1159
|
+
if (!aState || !bState)
|
|
1160
|
+
return a.distance - b.distance;
|
|
1161
|
+
return bState.events.priority - aState.events.priority || a.distance - b.distance;
|
|
368
1162
|
})
|
|
369
|
-
//
|
|
1163
|
+
// Filter out duplicates
|
|
370
1164
|
.filter((item) => {
|
|
371
1165
|
const id = makeId(item);
|
|
372
1166
|
if (duplicates.has(id))
|
|
@@ -374,10 +1168,11 @@ function createEvents(store) {
|
|
|
374
1168
|
duplicates.add(id);
|
|
375
1169
|
return true;
|
|
376
1170
|
});
|
|
377
|
-
//
|
|
1171
|
+
// https://github.com/mrdoob/three.js/issues/16031
|
|
1172
|
+
// Allow custom userland intersect sort order, this likely only makes sense on the root filter
|
|
378
1173
|
if (state.events.filter)
|
|
379
1174
|
hits = state.events.filter(hits, store);
|
|
380
|
-
//
|
|
1175
|
+
// Bubble up the events, find the event source (eventObject)
|
|
381
1176
|
for (const hit of hits) {
|
|
382
1177
|
let eventObject = hit.object;
|
|
383
1178
|
// bubble event up
|
|
@@ -388,20 +1183,19 @@ function createEvents(store) {
|
|
|
388
1183
|
eventObject = eventObject.parent;
|
|
389
1184
|
}
|
|
390
1185
|
}
|
|
391
|
-
//
|
|
1186
|
+
// If the interaction is captured, make all capturing targets part of the intersect.
|
|
392
1187
|
if ('pointerId' in event && state.internal.capturedMap.has(event.pointerId)) {
|
|
393
|
-
for (
|
|
394
|
-
if (!duplicates.has(makeId(
|
|
395
|
-
intersections.push(
|
|
396
|
-
}
|
|
1188
|
+
for (let captureData of state.internal.capturedMap.get(event.pointerId).values()) {
|
|
1189
|
+
if (!duplicates.has(makeId(captureData.intersection)))
|
|
1190
|
+
intersections.push(captureData.intersection);
|
|
397
1191
|
}
|
|
398
1192
|
}
|
|
399
1193
|
return intersections;
|
|
400
1194
|
}
|
|
401
|
-
/**
|
|
1195
|
+
/** Handles intersections by forwarding them to handlers */
|
|
402
1196
|
function handleIntersects(intersections, event, delta, callback) {
|
|
403
1197
|
const rootState = store.get();
|
|
404
|
-
//
|
|
1198
|
+
// If anything has been found, forward it to the event listeners
|
|
405
1199
|
if (intersections.length) {
|
|
406
1200
|
const localState = { stopped: false };
|
|
407
1201
|
for (const hit of intersections) {
|
|
@@ -412,14 +1206,17 @@ function createEvents(store) {
|
|
|
412
1206
|
const setPointerCapture = (id) => {
|
|
413
1207
|
const captureData = { intersection: hit, target: event.target };
|
|
414
1208
|
if (internal.capturedMap.has(id)) {
|
|
415
|
-
// if the pointerId was previously captured, we add the hit to the
|
|
1209
|
+
// if the pointerId was previously captured, we add the hit to the
|
|
1210
|
+
// event capturedMap.
|
|
416
1211
|
internal.capturedMap.get(id).set(hit.eventObject, captureData);
|
|
417
1212
|
}
|
|
418
1213
|
else {
|
|
419
|
-
// if the pointerId was not previously captured, we create a
|
|
1214
|
+
// if the pointerId was not previously captured, we create a map
|
|
1215
|
+
// containing the hitObject, and the hit. hitObject is used for
|
|
1216
|
+
// faster access.
|
|
420
1217
|
internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
|
|
421
1218
|
}
|
|
422
|
-
//
|
|
1219
|
+
// Call the original event now
|
|
423
1220
|
event.target.setPointerCapture(id);
|
|
424
1221
|
};
|
|
425
1222
|
const releasePointerCapture = (id) => {
|
|
@@ -428,15 +1225,15 @@ function createEvents(store) {
|
|
|
428
1225
|
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
429
1226
|
}
|
|
430
1227
|
};
|
|
431
|
-
//
|
|
1228
|
+
// Add native event props
|
|
432
1229
|
const extractEventProps = {};
|
|
433
1230
|
// 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.
|
|
434
|
-
for (
|
|
435
|
-
|
|
436
|
-
//
|
|
437
|
-
|
|
1231
|
+
for (let prop in event) {
|
|
1232
|
+
let property = event[prop];
|
|
1233
|
+
// Only copy over atomics, leave functions alone as these should be
|
|
1234
|
+
// called as event.nativeEvent.fn()
|
|
1235
|
+
if (typeof property !== 'function')
|
|
438
1236
|
extractEventProps[prop] = property;
|
|
439
|
-
}
|
|
440
1237
|
}
|
|
441
1238
|
const raycastEvent = {
|
|
442
1239
|
...hit,
|
|
@@ -447,7 +1244,7 @@ function createEvents(store) {
|
|
|
447
1244
|
delta,
|
|
448
1245
|
unprojectedPoint,
|
|
449
1246
|
ray: raycaster.ray,
|
|
450
|
-
camera
|
|
1247
|
+
camera,
|
|
451
1248
|
// Hijack stopPropagation, which just sets a flag
|
|
452
1249
|
stopPropagation() {
|
|
453
1250
|
// https://github.com/pmndrs/react-three-fiber/issues/596
|
|
@@ -475,9 +1272,9 @@ function createEvents(store) {
|
|
|
475
1272
|
currentTarget: { hasPointerCapture, setPointerCapture, releasePointerCapture },
|
|
476
1273
|
nativeEvent: event,
|
|
477
1274
|
};
|
|
478
|
-
//
|
|
1275
|
+
// Call subscribers
|
|
479
1276
|
callback(raycastEvent);
|
|
480
|
-
//
|
|
1277
|
+
// Event bubbling may be interrupted by stopPropagation
|
|
481
1278
|
if (localState.stopped === true)
|
|
482
1279
|
break;
|
|
483
1280
|
}
|
|
@@ -485,9 +1282,9 @@ function createEvents(store) {
|
|
|
485
1282
|
return intersections;
|
|
486
1283
|
}
|
|
487
1284
|
function cancelPointer(intersections) {
|
|
488
|
-
const
|
|
1285
|
+
const internal = store.get('internal');
|
|
489
1286
|
for (const hoveredObj of internal.hovered.values()) {
|
|
490
|
-
// When no objects were hit or the hovered object wasn't found underneath the cursor
|
|
1287
|
+
// When no objects were hit or the the hovered object wasn't found underneath the cursor
|
|
491
1288
|
// we call onPointerOut and delete the object from the hovered-elements map
|
|
492
1289
|
if (!intersections.length ||
|
|
493
1290
|
!intersections.find((hit) => hit.object === hoveredObj.object &&
|
|
@@ -531,14 +1328,14 @@ function createEvents(store) {
|
|
|
531
1328
|
}
|
|
532
1329
|
// Any other pointer goes here ...
|
|
533
1330
|
return function handleEvent(event) {
|
|
534
|
-
const
|
|
1331
|
+
const pointerMissed$ = store['pointerMissed$'];
|
|
1332
|
+
const internal = store.get('internal');
|
|
535
1333
|
// prepareRay(event)
|
|
536
1334
|
internal.lastEvent.nativeElement = event;
|
|
537
1335
|
// Get fresh intersects
|
|
538
1336
|
const isPointerMove = name === 'pointermove';
|
|
539
1337
|
const isClickEvent = name === 'click' || name === 'contextmenu' || name === 'dblclick';
|
|
540
1338
|
const filter = isPointerMove ? filterPointerEvents : undefined;
|
|
541
|
-
// const hits = patchIntersects(intersect(filter), event)
|
|
542
1339
|
const hits = intersect(event, filter);
|
|
543
1340
|
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
544
1341
|
// Save initial coordinates on pointer-down
|
|
@@ -551,8 +1348,7 @@ function createEvents(store) {
|
|
|
551
1348
|
if (isClickEvent && !hits.length) {
|
|
552
1349
|
if (delta <= 2) {
|
|
553
1350
|
pointerMissed(event, internal.interaction);
|
|
554
|
-
|
|
555
|
-
onPointerMissed(event);
|
|
1351
|
+
pointerMissed$.next(event);
|
|
556
1352
|
}
|
|
557
1353
|
}
|
|
558
1354
|
// Take care of unhover
|
|
@@ -565,6 +1361,20 @@ function createEvents(store) {
|
|
|
565
1361
|
// Check presence of handlers
|
|
566
1362
|
if (!instance?.eventCount)
|
|
567
1363
|
return;
|
|
1364
|
+
/*
|
|
1365
|
+
MAYBE TODO, DELETE IF NOT:
|
|
1366
|
+
Check if the object is captured, captured events should not have intersects running in parallel
|
|
1367
|
+
But wouldn't it be better to just replace capturedMap with a single entry?
|
|
1368
|
+
Also, are we OK with straight up making picking up multiple objects impossible?
|
|
1369
|
+
|
|
1370
|
+
const pointerId = (data as ThreeEvent<PointerEvent>).pointerId
|
|
1371
|
+
if (pointerId !== undefined) {
|
|
1372
|
+
const capturedMeshSet = internal.capturedMap.get(pointerId)
|
|
1373
|
+
if (capturedMeshSet) {
|
|
1374
|
+
const captured = capturedMeshSet.get(eventObject)
|
|
1375
|
+
if (captured && captured.localState.stopped) return
|
|
1376
|
+
}
|
|
1377
|
+
}*/
|
|
568
1378
|
if (isPointerMove) {
|
|
569
1379
|
// Move event ...
|
|
570
1380
|
if (handlers?.pointerover ||
|
|
@@ -659,6 +1469,11 @@ function createPointerEvents(store) {
|
|
|
659
1469
|
handlers[supportedEventName] = handlePointer(supportedEventName);
|
|
660
1470
|
return handlers;
|
|
661
1471
|
}, {}),
|
|
1472
|
+
update: () => {
|
|
1473
|
+
const { events, internal } = store.get();
|
|
1474
|
+
if (internal.lastEvent?.nativeElement && events.handlers)
|
|
1475
|
+
events.handlers.pointermove(internal.lastEvent.nativeElement);
|
|
1476
|
+
},
|
|
662
1477
|
connect: (target) => {
|
|
663
1478
|
const state = store.get();
|
|
664
1479
|
state.events.disconnect?.();
|
|
@@ -682,41 +1497,6 @@ function createPointerEvents(store) {
|
|
|
682
1497
|
};
|
|
683
1498
|
}
|
|
684
1499
|
|
|
685
|
-
function assertInjectionContext(fn, injector) {
|
|
686
|
-
try {
|
|
687
|
-
if (!injector) {
|
|
688
|
-
return inject(Injector);
|
|
689
|
-
}
|
|
690
|
-
return injector;
|
|
691
|
-
}
|
|
692
|
-
catch {
|
|
693
|
-
!injector && assertInInjectionContext(fn);
|
|
694
|
-
return null;
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
function safeDetectChanges(cdr) {
|
|
699
|
-
if (!cdr)
|
|
700
|
-
return;
|
|
701
|
-
try {
|
|
702
|
-
// dynamic created component with ViewContainerRef#createComponent does not have Context
|
|
703
|
-
// but it has _attachedToViewContainer
|
|
704
|
-
if (cdr['_attachedToViewContainer'] || !!cdr['context']) {
|
|
705
|
-
cdr.detectChanges();
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
catch (e) {
|
|
709
|
-
cdr.markForCheck();
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
function requestAnimationFrameInInjectionContext(cb, injector) {
|
|
714
|
-
injector = assertInjectionContext(requestAnimationFrameInInjectionContext, injector);
|
|
715
|
-
return requestAnimationFrame(() => {
|
|
716
|
-
return runInInjectionContext(injector, cb);
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
|
|
720
1500
|
const cached = new Map();
|
|
721
1501
|
function normalizeInputs(input) {
|
|
722
1502
|
if (Array.isArray(input))
|
|
@@ -752,702 +1532,160 @@ function injectNgtLoader(loaderConstructorFactory, inputs, { extensions, onProgr
|
|
|
752
1532
|
return runInInjectionContext(injector, () => {
|
|
753
1533
|
const cdr = inject(ChangeDetectorRef);
|
|
754
1534
|
const effector = load(loaderConstructorFactory, inputs, { extensions, onProgress });
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
}, {});
|
|
769
|
-
});
|
|
770
|
-
safeDetectChanges(cdr);
|
|
1535
|
+
effect(() => {
|
|
1536
|
+
const originalUrls = inputs();
|
|
1537
|
+
Promise.all(effector()).then((results) => {
|
|
1538
|
+
response.update(() => {
|
|
1539
|
+
if (Array.isArray(originalUrls))
|
|
1540
|
+
return results;
|
|
1541
|
+
if (typeof originalUrls === 'string')
|
|
1542
|
+
return results[0];
|
|
1543
|
+
const keys = Object.keys(originalUrls);
|
|
1544
|
+
return keys.reduce((result, key) => {
|
|
1545
|
+
result[key] = results[keys.indexOf(key)];
|
|
1546
|
+
return result;
|
|
1547
|
+
}, {});
|
|
771
1548
|
});
|
|
772
|
-
|
|
1549
|
+
safeDetectChanges(cdr);
|
|
1550
|
+
});
|
|
773
1551
|
});
|
|
774
1552
|
return response.asReadonly();
|
|
775
1553
|
});
|
|
776
1554
|
}
|
|
777
1555
|
injectNgtLoader['preload'] = (loaderConstructorFactory, inputs, extensions) => {
|
|
778
1556
|
Promise.all(load(loaderConstructorFactory, inputs, { extensions })());
|
|
779
|
-
};
|
|
780
|
-
injectNgtLoader['destroy'] = () => {
|
|
781
|
-
cached.clear();
|
|
782
|
-
};
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
const
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
function render(timestamp, store, frame) {
|
|
825
|
-
const state = store.get();
|
|
826
|
-
// Run local effects
|
|
827
|
-
let delta = state.clock.getDelta();
|
|
828
|
-
// In frameloop='never' mode, clock times are updated using the provided timestamp
|
|
829
|
-
if (state.frameloop === 'never' && typeof timestamp === 'number') {
|
|
830
|
-
delta = timestamp - state.clock.elapsedTime;
|
|
831
|
-
state.clock.oldTime = state.clock.elapsedTime;
|
|
832
|
-
state.clock.elapsedTime = timestamp;
|
|
833
|
-
}
|
|
834
|
-
// Call subscribers (useFrame)
|
|
835
|
-
const subscribers = state.internal.subscribers;
|
|
836
|
-
for (let i = 0; i < subscribers.length; i++) {
|
|
837
|
-
const subscription = subscribers[i];
|
|
838
|
-
subscription.callback({ ...subscription.store.get(), delta, frame });
|
|
839
|
-
}
|
|
840
|
-
// Render content
|
|
841
|
-
if (!state.internal.priority && state.gl.render)
|
|
842
|
-
state.gl.render(state.scene, state.camera);
|
|
843
|
-
// Decrease frame count
|
|
844
|
-
state.internal.frames = Math.max(0, state.internal.frames - 1);
|
|
845
|
-
return state.frameloop === 'always' ? 1 : state.internal.frames;
|
|
846
|
-
}
|
|
847
|
-
function createLoop(roots) {
|
|
848
|
-
let running = false;
|
|
849
|
-
let repeat;
|
|
850
|
-
let frame;
|
|
851
|
-
function loop(timestamp) {
|
|
852
|
-
frame = requestAnimationFrame(loop);
|
|
853
|
-
running = true;
|
|
854
|
-
repeat = 0;
|
|
855
|
-
// Run effects
|
|
856
|
-
flushGlobalEffects('before', timestamp);
|
|
857
|
-
// Render all roots
|
|
858
|
-
for (const root of roots.values()) {
|
|
859
|
-
const state = root.get();
|
|
860
|
-
// If the frameloop is invalidated, do not run another frame
|
|
861
|
-
if (state.internal.active &&
|
|
862
|
-
(state.frameloop === 'always' || state.internal.frames > 0) &&
|
|
863
|
-
!state.gl.xr?.isPresenting) {
|
|
864
|
-
repeat += render(timestamp, root);
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
// Run after-effects
|
|
868
|
-
flushGlobalEffects('after', timestamp);
|
|
869
|
-
// Stop the loop if nothing invalidates it
|
|
870
|
-
if (repeat === 0) {
|
|
871
|
-
// Tail call effects, they are called when rendering stops
|
|
872
|
-
flushGlobalEffects('tail', timestamp);
|
|
873
|
-
// Flag end of operation
|
|
874
|
-
running = false;
|
|
875
|
-
return cancelAnimationFrame(frame);
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
function invalidate(store, frames = 1) {
|
|
879
|
-
const state = store?.get();
|
|
880
|
-
if (!state)
|
|
881
|
-
return roots.forEach((root) => invalidate(root, frames));
|
|
882
|
-
if (state.gl.xr?.isPresenting || !state.internal.active || state.frameloop === 'never')
|
|
883
|
-
return;
|
|
884
|
-
// Increase frames, do not go higher than 60
|
|
885
|
-
state.internal.frames = Math.min(60, state.internal.frames + frames);
|
|
886
|
-
// If the render-loop isn't active, start it
|
|
887
|
-
if (!running) {
|
|
888
|
-
running = true;
|
|
889
|
-
requestAnimationFrame(loop);
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
function advance(timestamp, runGlobalEffects = true, store, frame) {
|
|
893
|
-
const state = store?.get();
|
|
894
|
-
if (runGlobalEffects)
|
|
895
|
-
flushGlobalEffects('before', timestamp);
|
|
896
|
-
if (!state)
|
|
897
|
-
for (const root of roots.values())
|
|
898
|
-
render(timestamp, root);
|
|
899
|
-
else
|
|
900
|
-
render(timestamp, store, frame);
|
|
901
|
-
if (runGlobalEffects)
|
|
902
|
-
flushGlobalEffects('after', timestamp);
|
|
903
|
-
}
|
|
904
|
-
return {
|
|
905
|
-
loop,
|
|
906
|
-
/**
|
|
907
|
-
* Invalidates the view, requesting a frame to be rendered. Will globally invalidate unless passed a root's state.
|
|
908
|
-
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#invalidate
|
|
909
|
-
*/
|
|
910
|
-
invalidate,
|
|
911
|
-
/**
|
|
912
|
-
* Advances the frameloop and runs render effects, useful for when manually rendering via `frameloop="never"`.
|
|
913
|
-
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#advance
|
|
914
|
-
*/
|
|
915
|
-
advance,
|
|
916
|
-
};
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
function diffProps(instance, props) {
|
|
920
|
-
const propsEntries = Object.entries(props);
|
|
921
|
-
const changes = [];
|
|
922
|
-
for (const [propKey, propValue] of propsEntries) {
|
|
923
|
-
let key = propKey;
|
|
924
|
-
if (is.colorSpaceExist(instance)) {
|
|
925
|
-
if (propKey === 'encoding') {
|
|
926
|
-
key = 'colorSpace';
|
|
927
|
-
}
|
|
928
|
-
else if (propKey === 'outputEncoding') {
|
|
929
|
-
key = 'outputColorSpace';
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
if (is.equ(propValue, instance[key]))
|
|
933
|
-
continue;
|
|
934
|
-
changes.push([propKey, propValue]);
|
|
935
|
-
}
|
|
936
|
-
return changes;
|
|
937
|
-
}
|
|
938
|
-
function applyProps(instance, props) {
|
|
939
|
-
// if props is empty
|
|
940
|
-
if (!Object.keys(props).length)
|
|
941
|
-
return instance;
|
|
942
|
-
// filter equals, events , and reserved props
|
|
943
|
-
const localState = getLocalState(instance);
|
|
944
|
-
const rootState = localState.store?.get();
|
|
945
|
-
const changes = diffProps(instance, props);
|
|
946
|
-
for (let i = 0; i < changes.length; i++) {
|
|
947
|
-
const currentInstance = instance;
|
|
948
|
-
let key = changes[i][0];
|
|
949
|
-
let value = changes[i][1];
|
|
950
|
-
if (is.colorSpaceExist(currentInstance)) {
|
|
951
|
-
const sRGBEncoding = 3001;
|
|
952
|
-
const SRGBColorSpace = 'srgb';
|
|
953
|
-
const LinearSRGBColorSpace = 'srgb-linear';
|
|
954
|
-
if (key === 'encoding') {
|
|
955
|
-
key = 'colorSpace';
|
|
956
|
-
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
957
|
-
}
|
|
958
|
-
else if (key === 'outputEncoding') {
|
|
959
|
-
key = 'outputColorSpace';
|
|
960
|
-
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
const targetProp = currentInstance[key];
|
|
964
|
-
// special treatmen for objects with support for set/copy, and layers
|
|
965
|
-
if (targetProp && targetProp['set'] && (targetProp['copy'] || targetProp instanceof THREE.Layers)) {
|
|
966
|
-
const isColor = targetProp instanceof THREE.Color;
|
|
967
|
-
// if value is an array
|
|
968
|
-
if (Array.isArray(value)) {
|
|
969
|
-
if (targetProp['fromArray'])
|
|
970
|
-
targetProp['fromArray'](value);
|
|
971
|
-
else
|
|
972
|
-
targetProp['set'](...value);
|
|
973
|
-
}
|
|
974
|
-
// test again target.copy
|
|
975
|
-
else if (targetProp['copy'] &&
|
|
976
|
-
value &&
|
|
977
|
-
value.constructor &&
|
|
978
|
-
targetProp.constructor.name === value.constructor.name) {
|
|
979
|
-
targetProp['copy'](value);
|
|
980
|
-
if (!THREE.ColorManagement && !rootState.linear && isColor)
|
|
981
|
-
targetProp['convertSRGBToLinear']();
|
|
982
|
-
}
|
|
983
|
-
// if nothing else fits, just set the single value, ignore undefined
|
|
984
|
-
else if (value !== undefined) {
|
|
985
|
-
const isColor = targetProp instanceof THREE.Color;
|
|
986
|
-
// allow setting array scalars
|
|
987
|
-
if (!isColor && targetProp['setScalar'])
|
|
988
|
-
targetProp['setScalar'](value);
|
|
989
|
-
// layers have no copy function, copy the mask
|
|
990
|
-
else if (targetProp instanceof THREE.Layers && value instanceof THREE.Layers)
|
|
991
|
-
targetProp.mask = value.mask;
|
|
992
|
-
// otherwise just set ...
|
|
993
|
-
else
|
|
994
|
-
targetProp['set'](value);
|
|
995
|
-
// auto-convert srgb
|
|
996
|
-
if (!THREE.ColorManagement && !rootState?.linear && isColor)
|
|
997
|
-
targetProp.convertSRGBToLinear();
|
|
1557
|
+
};
|
|
1558
|
+
injectNgtLoader['destroy'] = () => {
|
|
1559
|
+
cached.clear();
|
|
1560
|
+
};
|
|
1561
|
+
|
|
1562
|
+
const catalogue = {};
|
|
1563
|
+
function extend(objects) {
|
|
1564
|
+
Object.assign(catalogue, objects);
|
|
1565
|
+
}
|
|
1566
|
+
const [injectNgtCatalogue] = createInjectionToken(() => catalogue);
|
|
1567
|
+
|
|
1568
|
+
const ROUTED_SCENE = '__ngt_renderer_is_routed_scene__';
|
|
1569
|
+
const HTML = '__ngt_renderer_is_html';
|
|
1570
|
+
const SPECIAL_INTERNAL_ADD_COMMENT = '__ngt_renderer_add_comment__';
|
|
1571
|
+
const SPECIAL_DOM_TAG = {
|
|
1572
|
+
NGT_PORTAL: 'ngt-portal',
|
|
1573
|
+
NGT_PRIMITIVE: 'ngt-primitive',
|
|
1574
|
+
NGT_VALUE: 'ngt-value',
|
|
1575
|
+
};
|
|
1576
|
+
const SPECIAL_PROPERTIES = {
|
|
1577
|
+
COMPOUND: 'ngtCompound',
|
|
1578
|
+
RENDER_PRIORITY: 'priority',
|
|
1579
|
+
ATTACH: 'attach',
|
|
1580
|
+
VALUE: 'rawValue',
|
|
1581
|
+
REF: 'ref',
|
|
1582
|
+
};
|
|
1583
|
+
const SPECIAL_EVENTS = {
|
|
1584
|
+
BEFORE_RENDER: 'beforeRender',
|
|
1585
|
+
AFTER_UPDATE: 'afterUpdate',
|
|
1586
|
+
AFTER_ATTACH: 'afterAttach',
|
|
1587
|
+
};
|
|
1588
|
+
|
|
1589
|
+
class NgtCommonDirective {
|
|
1590
|
+
static { this.processComment = true; }
|
|
1591
|
+
constructor() {
|
|
1592
|
+
this.vcr = inject(ViewContainerRef);
|
|
1593
|
+
this.zone = inject(NgZone);
|
|
1594
|
+
this.template = inject(TemplateRef);
|
|
1595
|
+
this.injected = false;
|
|
1596
|
+
this.shouldCreateView = true;
|
|
1597
|
+
if (NgtCommonDirective.processComment) {
|
|
1598
|
+
const commentNode = this.vcr.element.nativeElement;
|
|
1599
|
+
if (commentNode[SPECIAL_INTERNAL_ADD_COMMENT]) {
|
|
1600
|
+
commentNode[SPECIAL_INTERNAL_ADD_COMMENT]();
|
|
1601
|
+
delete commentNode[SPECIAL_INTERNAL_ADD_COMMENT];
|
|
998
1602
|
}
|
|
999
1603
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
if (is.colorSpaceExist(texture) && is.colorSpaceExist(rootState.gl))
|
|
1010
|
-
texture.colorSpace = rootState.gl.outputColorSpace;
|
|
1011
|
-
else
|
|
1012
|
-
texture.encoding = rootState.gl.outputEncoding;
|
|
1604
|
+
inject(DestroyRef).onDestroy(() => {
|
|
1605
|
+
this.view?.destroy();
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
createView() {
|
|
1609
|
+
this.zone.runOutsideAngular(() => {
|
|
1610
|
+
if (this.shouldCreateView) {
|
|
1611
|
+
if (this.view && !this.view.destroyed) {
|
|
1612
|
+
this.view.destroy();
|
|
1013
1613
|
}
|
|
1614
|
+
this.view = this.vcr.createEmbeddedView(this.template);
|
|
1615
|
+
safeDetectChanges(this.view);
|
|
1014
1616
|
}
|
|
1015
|
-
}
|
|
1016
|
-
checkUpdate(targetProp);
|
|
1017
|
-
invalidateInstance(instance);
|
|
1018
|
-
}
|
|
1019
|
-
const instanceHandlers = localState.eventCount;
|
|
1020
|
-
const parent = localState.parent ? untracked(localState.parent) : null;
|
|
1021
|
-
if (parent && rootState.internal && instance['raycast'] && instanceHandlers !== localState.eventCount) {
|
|
1022
|
-
// Pre-emptively remove the instance from the interaction manager
|
|
1023
|
-
const index = rootState.internal.interaction.indexOf(instance);
|
|
1024
|
-
if (index > -1)
|
|
1025
|
-
rootState.internal.interaction.splice(index, 1);
|
|
1026
|
-
// Add the instance to the interaction manager only when it has handlers
|
|
1027
|
-
if (localState.eventCount)
|
|
1028
|
-
rootState.internal.interaction.push(instance);
|
|
1029
|
-
}
|
|
1030
|
-
if (parent && localState.afterUpdate && localState.afterUpdate.observed && changes.length) {
|
|
1031
|
-
localState.afterUpdate.emit(instance);
|
|
1617
|
+
});
|
|
1032
1618
|
}
|
|
1033
|
-
|
|
1619
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtCommonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1620
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.1.7", type: NgtCommonDirective, ngImport: i0 }); }
|
|
1034
1621
|
}
|
|
1622
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtCommonDirective, decorators: [{
|
|
1623
|
+
type: Directive
|
|
1624
|
+
}], ctorParameters: function () { return []; } });
|
|
1035
1625
|
|
|
1036
|
-
|
|
1037
|
-
const { invalidate, advance } = createLoop(rootStateMap);
|
|
1038
|
-
const shallowLoose = { objects: 'shallow', strict: false };
|
|
1039
|
-
class NgtStore extends NgtSignalStore {
|
|
1626
|
+
class NgtArgs extends NgtCommonDirective {
|
|
1040
1627
|
constructor() {
|
|
1041
1628
|
super(...arguments);
|
|
1042
|
-
this
|
|
1043
|
-
this.#window = inject(DOCUMENT).defaultView;
|
|
1044
|
-
this.#injector = inject(Injector);
|
|
1045
|
-
this.isInit = false;
|
|
1046
|
-
}
|
|
1047
|
-
#parentStore;
|
|
1048
|
-
#window;
|
|
1049
|
-
#injector;
|
|
1050
|
-
init() {
|
|
1051
|
-
if (!this.isInit) {
|
|
1052
|
-
const position = new THREE.Vector3();
|
|
1053
|
-
const defaultTarget = new THREE.Vector3();
|
|
1054
|
-
const tempTarget = new THREE.Vector3();
|
|
1055
|
-
const getCurrentViewport = (camera = this.get('camera'), target = defaultTarget, size = this.get('size')) => {
|
|
1056
|
-
const { width, height, top, left } = size;
|
|
1057
|
-
const aspect = width / height;
|
|
1058
|
-
if (target instanceof THREE.Vector3)
|
|
1059
|
-
tempTarget.copy(target);
|
|
1060
|
-
else
|
|
1061
|
-
tempTarget.set(...target);
|
|
1062
|
-
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
1063
|
-
if (is.orthographicCamera(camera)) {
|
|
1064
|
-
return {
|
|
1065
|
-
width: width / camera.zoom,
|
|
1066
|
-
height: height / camera.zoom,
|
|
1067
|
-
top,
|
|
1068
|
-
left,
|
|
1069
|
-
factor: 1,
|
|
1070
|
-
distance,
|
|
1071
|
-
aspect,
|
|
1072
|
-
};
|
|
1073
|
-
}
|
|
1074
|
-
const fov = (camera.fov * Math.PI) / 180; // convert vertical fov to radians
|
|
1075
|
-
const h = 2 * Math.tan(fov / 2) * distance; // visible height
|
|
1076
|
-
const w = h * aspect;
|
|
1077
|
-
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
1078
|
-
};
|
|
1079
|
-
let performanceTimeout;
|
|
1080
|
-
const setPerformanceCurrent = (current) => {
|
|
1081
|
-
this.set((state) => ({ performance: { ...state.performance, current } }));
|
|
1082
|
-
};
|
|
1083
|
-
this.set({
|
|
1084
|
-
get: this.get.bind(this),
|
|
1085
|
-
set: this.set.bind(this),
|
|
1086
|
-
ready: false,
|
|
1087
|
-
events: { priority: 1, enabled: true, connected: false },
|
|
1088
|
-
invalidate: (frames = 1) => invalidate(this, frames),
|
|
1089
|
-
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, this),
|
|
1090
|
-
legacy: false,
|
|
1091
|
-
linear: false,
|
|
1092
|
-
flat: false,
|
|
1093
|
-
controls: null,
|
|
1094
|
-
clock: new THREE.Clock(),
|
|
1095
|
-
pointer: new THREE.Vector2(),
|
|
1096
|
-
frameloop: 'always',
|
|
1097
|
-
performance: {
|
|
1098
|
-
current: 1,
|
|
1099
|
-
min: 0.5,
|
|
1100
|
-
max: 1,
|
|
1101
|
-
debounce: 200,
|
|
1102
|
-
regress: () => {
|
|
1103
|
-
const state = this.get();
|
|
1104
|
-
// clear timeout
|
|
1105
|
-
if (performanceTimeout)
|
|
1106
|
-
clearTimeout(performanceTimeout);
|
|
1107
|
-
// set lower bound
|
|
1108
|
-
if (state.performance.current !== state.performance.min)
|
|
1109
|
-
setPerformanceCurrent(state.performance.min);
|
|
1110
|
-
// go back to upper bound
|
|
1111
|
-
performanceTimeout = setTimeout(() => {
|
|
1112
|
-
setPerformanceCurrent(this.get('performance', 'max') || 1);
|
|
1113
|
-
}, state.performance.debounce);
|
|
1114
|
-
},
|
|
1115
|
-
},
|
|
1116
|
-
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
1117
|
-
viewport: {
|
|
1118
|
-
initialDpr: 0,
|
|
1119
|
-
dpr: 0,
|
|
1120
|
-
width: 0,
|
|
1121
|
-
height: 0,
|
|
1122
|
-
top: 0,
|
|
1123
|
-
left: 0,
|
|
1124
|
-
aspect: 0,
|
|
1125
|
-
distance: 0,
|
|
1126
|
-
factor: 0,
|
|
1127
|
-
getCurrentViewport,
|
|
1128
|
-
},
|
|
1129
|
-
previousStore: this.#parentStore,
|
|
1130
|
-
internal: {
|
|
1131
|
-
active: false,
|
|
1132
|
-
priority: 0,
|
|
1133
|
-
frames: 0,
|
|
1134
|
-
lastEvent: new ElementRef(null),
|
|
1135
|
-
interaction: [],
|
|
1136
|
-
hovered: new Map(),
|
|
1137
|
-
subscribers: [],
|
|
1138
|
-
initialClick: [0, 0],
|
|
1139
|
-
initialHits: [],
|
|
1140
|
-
capturedMap: new Map(),
|
|
1141
|
-
subscribe: (callback, priority = 0, store = this) => {
|
|
1142
|
-
const internal = this.get('internal');
|
|
1143
|
-
// If this subscription was given a priority, it takes rendering into its own hands
|
|
1144
|
-
// For that reason we switch off automatic rendering and increase the manual flag
|
|
1145
|
-
// As long as this flag is positive there can be no internal rendering at all
|
|
1146
|
-
// because there could be multiple render subscriptions
|
|
1147
|
-
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1148
|
-
internal.subscribers.push({ priority, store, callback });
|
|
1149
|
-
// Register subscriber and sort layers from lowest to highest, meaning,
|
|
1150
|
-
// highest priority renders last (on top of the other frames)
|
|
1151
|
-
internal.subscribers.sort((a, b) => (a.priority || 0) - (b.priority || 0));
|
|
1152
|
-
return () => {
|
|
1153
|
-
const internal = this.get('internal');
|
|
1154
|
-
if (internal?.subscribers) {
|
|
1155
|
-
// Decrease manual flag if this subscription had a priority
|
|
1156
|
-
internal.priority = internal.priority - (priority > 0 ? 1 : 0);
|
|
1157
|
-
// Remove subscriber from list
|
|
1158
|
-
internal.subscribers = internal.subscribers.filter((s) => s.callback !== callback);
|
|
1159
|
-
}
|
|
1160
|
-
};
|
|
1161
|
-
},
|
|
1162
|
-
},
|
|
1163
|
-
setEvents: (events) => {
|
|
1164
|
-
this.set((state) => ({ events: { ...state.events, ...events } }));
|
|
1165
|
-
},
|
|
1166
|
-
setSize: (width, height, top, left) => {
|
|
1167
|
-
const camera = this.get('camera');
|
|
1168
|
-
const size = { width, height, top: top || 0, left: left || 0 };
|
|
1169
|
-
this.set((state) => ({
|
|
1170
|
-
size,
|
|
1171
|
-
viewport: { ...state.viewport, ...getCurrentViewport(camera, defaultTarget, size) },
|
|
1172
|
-
}));
|
|
1173
|
-
},
|
|
1174
|
-
setDpr: (dpr) => {
|
|
1175
|
-
const resolved = makeDpr(dpr, this.#window);
|
|
1176
|
-
this.set((state) => ({
|
|
1177
|
-
viewport: {
|
|
1178
|
-
...state.viewport,
|
|
1179
|
-
dpr: resolved,
|
|
1180
|
-
initialDpr: state.viewport.initialDpr || resolved,
|
|
1181
|
-
},
|
|
1182
|
-
}));
|
|
1183
|
-
},
|
|
1184
|
-
setFrameloop: (frameloop = 'always') => {
|
|
1185
|
-
const clock = this.get('clock');
|
|
1186
|
-
clock.stop();
|
|
1187
|
-
clock.elapsedTime = 0;
|
|
1188
|
-
if (frameloop !== 'never') {
|
|
1189
|
-
clock.start();
|
|
1190
|
-
clock.elapsedTime = 0;
|
|
1191
|
-
}
|
|
1192
|
-
this.set({ frameloop });
|
|
1193
|
-
},
|
|
1194
|
-
});
|
|
1195
|
-
this.isInit = true;
|
|
1196
|
-
this.#resize();
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
configure(inputs, canvasElement) {
|
|
1200
|
-
const { gl: glOptions, size: sizeOptions, camera: cameraOptions, raycaster: raycasterOptions, scene: sceneOptions, events, orthographic, lookAt, shadows, linear, legacy, flat, dpr, frameloop, performance, } = inputs;
|
|
1201
|
-
const state = this.get();
|
|
1202
|
-
const stateToUpdate = {};
|
|
1203
|
-
// setup renderer
|
|
1204
|
-
let gl = state.gl;
|
|
1205
|
-
if (!state.gl)
|
|
1206
|
-
stateToUpdate.gl = gl = makeDefaultRenderer(glOptions, canvasElement);
|
|
1207
|
-
// setup raycaster
|
|
1208
|
-
let raycaster = state.raycaster;
|
|
1209
|
-
if (!raycaster)
|
|
1210
|
-
stateToUpdate.raycaster = raycaster = new THREE.Raycaster();
|
|
1211
|
-
// set raycaster options
|
|
1212
|
-
const { params, ...options } = raycasterOptions || {};
|
|
1213
|
-
if (!is.equ(options, raycaster, shallowLoose))
|
|
1214
|
-
applyProps(raycaster, { ...options });
|
|
1215
|
-
if (!is.equ(params, raycaster.params, shallowLoose)) {
|
|
1216
|
-
applyProps(raycaster, { params: { ...raycaster.params, ...(params || {}) } });
|
|
1217
|
-
}
|
|
1218
|
-
// create default camera
|
|
1219
|
-
if (!state.camera) {
|
|
1220
|
-
const isCamera = is.camera(cameraOptions);
|
|
1221
|
-
let camera = isCamera ? cameraOptions : makeDefaultCamera(orthographic || false, state.size);
|
|
1222
|
-
if (!isCamera) {
|
|
1223
|
-
if (cameraOptions)
|
|
1224
|
-
applyProps(camera, cameraOptions);
|
|
1225
|
-
// set position.z
|
|
1226
|
-
if (!cameraOptions?.position)
|
|
1227
|
-
camera.position.z = 5;
|
|
1228
|
-
// always look at center or passed-in lookAt by default
|
|
1229
|
-
if (!cameraOptions?.rotation && !cameraOptions?.quaternion) {
|
|
1230
|
-
if (Array.isArray(lookAt))
|
|
1231
|
-
camera.lookAt(lookAt[0], lookAt[1], lookAt[2]);
|
|
1232
|
-
else if (lookAt instanceof THREE.Vector3)
|
|
1233
|
-
camera.lookAt(lookAt);
|
|
1234
|
-
else
|
|
1235
|
-
camera.lookAt(0, 0, 0);
|
|
1236
|
-
}
|
|
1237
|
-
// update projection matrix after applyprops
|
|
1238
|
-
camera.updateProjectionMatrix?.();
|
|
1239
|
-
}
|
|
1240
|
-
if (!is.instance(camera))
|
|
1241
|
-
camera = prepare(camera, { store: this });
|
|
1242
|
-
stateToUpdate.camera = camera;
|
|
1243
|
-
}
|
|
1244
|
-
// Set up scene (one time only!)
|
|
1245
|
-
if (!state.scene) {
|
|
1246
|
-
let scene;
|
|
1247
|
-
if (sceneOptions instanceof THREE.Scene) {
|
|
1248
|
-
scene = prepare(sceneOptions, { store: this });
|
|
1249
|
-
}
|
|
1250
|
-
else {
|
|
1251
|
-
scene = prepare(new THREE.Scene(), { store: this });
|
|
1252
|
-
if (sceneOptions)
|
|
1253
|
-
applyProps(scene, sceneOptions);
|
|
1254
|
-
}
|
|
1255
|
-
stateToUpdate.scene = scene;
|
|
1256
|
-
}
|
|
1257
|
-
// Set up XR (one time only!)
|
|
1258
|
-
if (!state.xr) {
|
|
1259
|
-
// Handle frame behavior in WebXR
|
|
1260
|
-
const handleXRFrame = (timestamp, frame) => {
|
|
1261
|
-
const state = this.get();
|
|
1262
|
-
if (state.frameloop === 'never')
|
|
1263
|
-
return;
|
|
1264
|
-
advance(timestamp, true, this, frame);
|
|
1265
|
-
};
|
|
1266
|
-
// Toggle render switching on session
|
|
1267
|
-
const handleSessionChange = () => {
|
|
1268
|
-
const state = this.get();
|
|
1269
|
-
state.gl.xr.enabled = state.gl.xr.isPresenting;
|
|
1270
|
-
state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
|
|
1271
|
-
if (!state.gl.xr.isPresenting)
|
|
1272
|
-
state.invalidate();
|
|
1273
|
-
};
|
|
1274
|
-
// WebXR session manager
|
|
1275
|
-
const xr = {
|
|
1276
|
-
connect: () => {
|
|
1277
|
-
gl.xr.addEventListener('sessionstart', handleSessionChange);
|
|
1278
|
-
gl.xr.addEventListener('sessionend', handleSessionChange);
|
|
1279
|
-
},
|
|
1280
|
-
disconnect: () => {
|
|
1281
|
-
gl.xr.removeEventListener('sessionstart', handleSessionChange);
|
|
1282
|
-
gl.xr.removeEventListener('sessionend', handleSessionChange);
|
|
1283
|
-
},
|
|
1284
|
-
};
|
|
1285
|
-
// Subscribe to WebXR session events
|
|
1286
|
-
if (gl.xr)
|
|
1287
|
-
xr.connect();
|
|
1288
|
-
stateToUpdate.xr = xr;
|
|
1289
|
-
}
|
|
1290
|
-
// Set shadowmap
|
|
1291
|
-
if (gl.shadowMap) {
|
|
1292
|
-
const oldEnabled = gl.shadowMap.enabled;
|
|
1293
|
-
const oldType = gl.shadowMap.type;
|
|
1294
|
-
gl.shadowMap.enabled = !!shadows;
|
|
1295
|
-
if (typeof shadows === 'boolean') {
|
|
1296
|
-
gl.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
1297
|
-
}
|
|
1298
|
-
else if (typeof shadows === 'string') {
|
|
1299
|
-
const types = {
|
|
1300
|
-
basic: THREE.BasicShadowMap,
|
|
1301
|
-
percentage: THREE.PCFShadowMap,
|
|
1302
|
-
soft: THREE.PCFSoftShadowMap,
|
|
1303
|
-
variance: THREE.VSMShadowMap,
|
|
1304
|
-
};
|
|
1305
|
-
gl.shadowMap.type = types[shadows] ?? THREE.PCFSoftShadowMap;
|
|
1306
|
-
}
|
|
1307
|
-
else if (is.obj(shadows)) {
|
|
1308
|
-
Object.assign(gl.shadowMap, shadows);
|
|
1309
|
-
}
|
|
1310
|
-
if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type)
|
|
1311
|
-
checkNeedsUpdate(gl.shadowMap);
|
|
1312
|
-
}
|
|
1313
|
-
// Safely set color management if available.
|
|
1314
|
-
// Avoid accessing THREE.ColorManagement to play nice with older versions
|
|
1315
|
-
if (THREE.ColorManagement) {
|
|
1316
|
-
const ColorManagement = THREE.ColorManagement;
|
|
1317
|
-
if ('enabled' in ColorManagement)
|
|
1318
|
-
ColorManagement['enabled'] = !legacy ?? false;
|
|
1319
|
-
else if ('legacyMode' in ColorManagement)
|
|
1320
|
-
ColorManagement['legacyMode'] = legacy ?? true;
|
|
1321
|
-
}
|
|
1322
|
-
// set color space and tonemapping preferences
|
|
1323
|
-
const LinearEncoding = 3000;
|
|
1324
|
-
const sRGBEncoding = 3001;
|
|
1325
|
-
applyProps(gl, {
|
|
1326
|
-
outputEncoding: linear ? LinearEncoding : sRGBEncoding,
|
|
1327
|
-
toneMapping: flat ? THREE.NoToneMapping : THREE.ACESFilmicToneMapping,
|
|
1328
|
-
});
|
|
1329
|
-
// Update color management state
|
|
1330
|
-
if (state.legacy !== legacy)
|
|
1331
|
-
stateToUpdate.legacy = legacy;
|
|
1332
|
-
if (state.linear !== linear)
|
|
1333
|
-
stateToUpdate.linear = linear;
|
|
1334
|
-
if (state.flat !== flat)
|
|
1335
|
-
stateToUpdate.flat = flat;
|
|
1336
|
-
// Set gl props
|
|
1337
|
-
gl.setClearAlpha(0);
|
|
1338
|
-
gl.setPixelRatio(makeDpr(state.viewport.dpr));
|
|
1339
|
-
gl.setSize(state.size.width, state.size.height);
|
|
1340
|
-
if (is.obj(glOptions) &&
|
|
1341
|
-
!(typeof glOptions === 'function') &&
|
|
1342
|
-
!is.renderer(glOptions) &&
|
|
1343
|
-
!is.equ(glOptions, gl, shallowLoose)) {
|
|
1344
|
-
applyProps(gl, glOptions);
|
|
1345
|
-
}
|
|
1346
|
-
// Store events internally
|
|
1347
|
-
if (events && !state.events.handlers)
|
|
1348
|
-
stateToUpdate.events = events(this);
|
|
1349
|
-
// Check performance
|
|
1350
|
-
if (performance && !is.equ(performance, state.performance, shallowLoose)) {
|
|
1351
|
-
stateToUpdate.performance = { ...state.performance, ...performance };
|
|
1352
|
-
}
|
|
1353
|
-
this.set(stateToUpdate);
|
|
1354
|
-
// Check pixelratio
|
|
1355
|
-
if (dpr && state.viewport.dpr !== makeDpr(dpr))
|
|
1356
|
-
state.setDpr(dpr);
|
|
1357
|
-
// Check size, allow it to take on container bounds initially
|
|
1358
|
-
const size = computeInitialSize(canvasElement, sizeOptions);
|
|
1359
|
-
if (!is.equ(size, state.size, shallowLoose))
|
|
1360
|
-
state.setSize(size.width, size.height, size.top, size.left);
|
|
1361
|
-
// Check frameloop
|
|
1362
|
-
if (state.frameloop !== frameloop)
|
|
1363
|
-
state.setFrameloop(frameloop);
|
|
1364
|
-
if (!this.get('ready'))
|
|
1365
|
-
this.set({ ready: true });
|
|
1366
|
-
this.#invalidate();
|
|
1367
|
-
}
|
|
1368
|
-
destroy(canvas) {
|
|
1369
|
-
this.set((state) => ({ internal: { ...state.internal, active: false } }));
|
|
1370
|
-
setTimeout(() => {
|
|
1371
|
-
const { gl, xr, events } = this.get();
|
|
1372
|
-
if (gl) {
|
|
1373
|
-
if (events.disconnect) {
|
|
1374
|
-
events.disconnect();
|
|
1375
|
-
}
|
|
1376
|
-
gl.renderLists.dispose();
|
|
1377
|
-
gl.forceContextLoss();
|
|
1378
|
-
if (gl.xr && gl.xr.enabled) {
|
|
1379
|
-
gl.xr.setAnimationLoop(null);
|
|
1380
|
-
xr.disconnect();
|
|
1381
|
-
}
|
|
1382
|
-
dispose(this.get());
|
|
1383
|
-
rootStateMap.delete(canvas);
|
|
1384
|
-
}
|
|
1385
|
-
}, 500);
|
|
1629
|
+
this.injectedArgs = [];
|
|
1386
1630
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
oldSize = size;
|
|
1401
|
-
oldDpr = viewport.dpr;
|
|
1402
|
-
// update camera
|
|
1403
|
-
updateCamera(camera, size);
|
|
1404
|
-
gl.setPixelRatio(viewport.dpr);
|
|
1405
|
-
gl.setSize(size.width, size.height);
|
|
1406
|
-
}
|
|
1407
|
-
// update viewport when camera changes
|
|
1408
|
-
if (camera !== oldCamera) {
|
|
1409
|
-
oldCamera = camera;
|
|
1410
|
-
updateCamera(camera, size);
|
|
1411
|
-
this.set((state) => ({
|
|
1412
|
-
viewport: { ...state.viewport, ...state.viewport.getCurrentViewport(camera) },
|
|
1413
|
-
}));
|
|
1414
|
-
}
|
|
1415
|
-
}, { injector: this.#injector, allowSignalWrites: true });
|
|
1631
|
+
set args(args) {
|
|
1632
|
+
if (args == null || !Array.isArray(args) || (args.length === 1 && args[0] === null))
|
|
1633
|
+
return;
|
|
1634
|
+
this.injected = false;
|
|
1635
|
+
this.injectedArgs = args;
|
|
1636
|
+
this.createView();
|
|
1637
|
+
}
|
|
1638
|
+
get args() {
|
|
1639
|
+
if (this.validate()) {
|
|
1640
|
+
this.injected = true;
|
|
1641
|
+
return this.injectedArgs;
|
|
1642
|
+
}
|
|
1643
|
+
return null;
|
|
1416
1644
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1645
|
+
validate() {
|
|
1646
|
+
return !this.injected && !!this.injectedArgs.length;
|
|
1419
1647
|
}
|
|
1420
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
1421
|
-
static { this.ɵ
|
|
1648
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtArgs, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1649
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.1.7", type: NgtArgs, isStandalone: true, selector: "ng-template[args]", inputs: { args: "args" }, usesInheritance: true, ngImport: i0 }); }
|
|
1422
1650
|
}
|
|
1423
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
1424
|
-
type:
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1651
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtArgs, decorators: [{
|
|
1652
|
+
type: Directive,
|
|
1653
|
+
args: [{ selector: 'ng-template[args]', standalone: true }]
|
|
1654
|
+
}], propDecorators: { args: [{
|
|
1655
|
+
type: Input
|
|
1656
|
+
}] } });
|
|
1657
|
+
|
|
1658
|
+
class NgtParent extends NgtCommonDirective {
|
|
1659
|
+
constructor() {
|
|
1660
|
+
super(...arguments);
|
|
1661
|
+
this.injectedParent = null;
|
|
1431
1662
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1663
|
+
set parent(parent) {
|
|
1664
|
+
if (!parent)
|
|
1665
|
+
return;
|
|
1666
|
+
this.injected = false;
|
|
1667
|
+
this.injectedParent = parent;
|
|
1668
|
+
this.createView();
|
|
1669
|
+
}
|
|
1670
|
+
get parent() {
|
|
1671
|
+
if (this.validate()) {
|
|
1672
|
+
this.injected = true;
|
|
1673
|
+
return this.injectedParent;
|
|
1674
|
+
}
|
|
1675
|
+
return null;
|
|
1441
1676
|
}
|
|
1677
|
+
validate() {
|
|
1678
|
+
return !this.injected && !!this.injectedParent;
|
|
1679
|
+
}
|
|
1680
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtParent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1681
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.1.7", type: NgtParent, isStandalone: true, selector: "ng-template[parent]", inputs: { parent: "parent" }, usesInheritance: true, ngImport: i0 }); }
|
|
1442
1682
|
}
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
}
|
|
1450
|
-
const NGT_CATALOGUE = new InjectionToken('THREE Constructors Catalogue', { factory: () => catalogue });
|
|
1683
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtParent, decorators: [{
|
|
1684
|
+
type: Directive,
|
|
1685
|
+
args: [{ selector: 'ng-template[parent]', standalone: true }]
|
|
1686
|
+
}], propDecorators: { parent: [{
|
|
1687
|
+
type: Input
|
|
1688
|
+
}] } });
|
|
1451
1689
|
|
|
1452
1690
|
function attach(object, value, paths = []) {
|
|
1453
1691
|
const [base, ...remaining] = paths;
|
|
@@ -1479,25 +1717,6 @@ function createAttachFunction(cb) {
|
|
|
1479
1717
|
return (parent, child, store) => cb({ parent, child, store });
|
|
1480
1718
|
}
|
|
1481
1719
|
|
|
1482
|
-
const ROUTED_SCENE = '__ngt_renderer_is_routed_scene__';
|
|
1483
|
-
const SPECIAL_INTERNAL_ADD_COMMENT = '__ngt_renderer_add_comment__';
|
|
1484
|
-
const SPECIAL_DOM_TAG = {
|
|
1485
|
-
NGT_PORTAL: 'ngt-portal',
|
|
1486
|
-
NGT_PRIMITIVE: 'ngt-primitive',
|
|
1487
|
-
NGT_VALUE: 'ngt-value',
|
|
1488
|
-
};
|
|
1489
|
-
const SPECIAL_PROPERTIES = {
|
|
1490
|
-
COMPOUND: 'ngtCompound',
|
|
1491
|
-
RENDER_PRIORITY: 'priority',
|
|
1492
|
-
ATTACH: 'attach',
|
|
1493
|
-
VALUE: 'rawValue',
|
|
1494
|
-
REF: 'ref',
|
|
1495
|
-
};
|
|
1496
|
-
const SPECIAL_EVENTS = {
|
|
1497
|
-
BEFORE_RENDER: 'beforeRender',
|
|
1498
|
-
AFTER_UPDATE: 'afterUpdate',
|
|
1499
|
-
AFTER_ATTACH: 'afterAttach',
|
|
1500
|
-
};
|
|
1501
1720
|
function attachThreeChild(parent, child) {
|
|
1502
1721
|
const pLS = getLocalState(parent);
|
|
1503
1722
|
const cLS = getLocalState(child);
|
|
@@ -1508,7 +1727,7 @@ function attachThreeChild(parent, child) {
|
|
|
1508
1727
|
let added = false;
|
|
1509
1728
|
// assign store on child if not already exist
|
|
1510
1729
|
// or child store is the parent of parent store
|
|
1511
|
-
if (!cLS.store || cLS.store === pLS.store.get('
|
|
1730
|
+
if (!cLS.store || cLS.store === pLS.store.get('previousRoot')) {
|
|
1512
1731
|
cLS.store = pLS.store;
|
|
1513
1732
|
}
|
|
1514
1733
|
if (cLS.attach) {
|
|
@@ -1534,8 +1753,8 @@ function attachThreeChild(parent, child) {
|
|
|
1534
1753
|
}
|
|
1535
1754
|
// attach
|
|
1536
1755
|
if (cLS.isRaw) {
|
|
1537
|
-
if (cLS.parent) {
|
|
1538
|
-
|
|
1756
|
+
if (cLS.parent && cLS.parent() !== parent) {
|
|
1757
|
+
untracked(() => {
|
|
1539
1758
|
cLS.parent.set(parent);
|
|
1540
1759
|
});
|
|
1541
1760
|
}
|
|
@@ -1556,8 +1775,8 @@ function attachThreeChild(parent, child) {
|
|
|
1556
1775
|
added = true;
|
|
1557
1776
|
}
|
|
1558
1777
|
pLS.add(child, added ? 'objects' : 'nonObjects');
|
|
1559
|
-
if (cLS.parent) {
|
|
1560
|
-
|
|
1778
|
+
if (cLS.parent && cLS.parent() !== parent) {
|
|
1779
|
+
untracked(() => {
|
|
1561
1780
|
cLS.parent.set(parent);
|
|
1562
1781
|
});
|
|
1563
1782
|
}
|
|
@@ -1570,7 +1789,7 @@ function removeThreeChild(parent, child, dispose) {
|
|
|
1570
1789
|
const pLS = getLocalState(parent);
|
|
1571
1790
|
const cLS = getLocalState(child);
|
|
1572
1791
|
// clear parent ref
|
|
1573
|
-
|
|
1792
|
+
untracked(() => {
|
|
1574
1793
|
cLS.parent?.set(null);
|
|
1575
1794
|
});
|
|
1576
1795
|
// remove child from parent
|
|
@@ -1600,7 +1819,15 @@ function removeThreeRecursive(array, parent, dispose) {
|
|
|
1600
1819
|
if (array)
|
|
1601
1820
|
[...array].forEach((child) => removeThreeChild(parent, child, dispose));
|
|
1602
1821
|
}
|
|
1603
|
-
function
|
|
1822
|
+
function kebabToPascal(str) {
|
|
1823
|
+
// split the string at each hyphen
|
|
1824
|
+
const parts = str.split('-');
|
|
1825
|
+
// map over the parts, capitalizing the first letter of each part
|
|
1826
|
+
const pascalParts = parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1));
|
|
1827
|
+
// join the parts together to create the final PascalCase string
|
|
1828
|
+
return pascalParts.join('');
|
|
1829
|
+
}
|
|
1830
|
+
function processThreeEvent(instance, priority, eventName, callback, zone, rootCdr, targetCdr) {
|
|
1604
1831
|
const lS = getLocalState(instance);
|
|
1605
1832
|
if (eventName === SPECIAL_EVENTS.BEFORE_RENDER) {
|
|
1606
1833
|
return lS.store
|
|
@@ -1624,8 +1851,7 @@ function processThreeEvent(instance, priority, eventName, callback, zone, cdr, t
|
|
|
1624
1851
|
previousHandler(event);
|
|
1625
1852
|
zone.run(() => {
|
|
1626
1853
|
callback(event);
|
|
1627
|
-
safeDetectChanges(targetCdr);
|
|
1628
|
-
safeDetectChanges(cdr);
|
|
1854
|
+
safeDetectChanges(targetCdr, rootCdr);
|
|
1629
1855
|
});
|
|
1630
1856
|
};
|
|
1631
1857
|
Object.assign(lS.handlers, { [eventName]: updatedCallback });
|
|
@@ -1639,6 +1865,7 @@ function processThreeEvent(instance, priority, eventName, callback, zone, cdr, t
|
|
|
1639
1865
|
return () => {
|
|
1640
1866
|
const localState = getLocalState(instance);
|
|
1641
1867
|
if (localState && localState.eventCount) {
|
|
1868
|
+
localState.eventCount -= 1;
|
|
1642
1869
|
const index = localState.store
|
|
1643
1870
|
.get('internal', 'interaction')
|
|
1644
1871
|
.findIndex((obj) => obj.uuid === instance.uuid);
|
|
@@ -1647,117 +1874,12 @@ function processThreeEvent(instance, priority, eventName, callback, zone, cdr, t
|
|
|
1647
1874
|
}
|
|
1648
1875
|
};
|
|
1649
1876
|
}
|
|
1650
|
-
function eventToHandler(callback) {
|
|
1651
|
-
return (event) => {
|
|
1652
|
-
callback(event);
|
|
1653
|
-
};
|
|
1654
|
-
}
|
|
1655
|
-
function kebabToPascal(str) {
|
|
1656
|
-
// split the string at each hyphen
|
|
1657
|
-
const parts = str.split('-');
|
|
1658
|
-
// map over the parts, capitalizing the first letter of each part
|
|
1659
|
-
const pascalParts = parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1));
|
|
1660
|
-
// join the parts together to create the final PascalCase string
|
|
1661
|
-
return pascalParts.join('');
|
|
1662
|
-
}
|
|
1663
|
-
|
|
1664
|
-
class NgtCommonDirective {
|
|
1665
|
-
#vcr;
|
|
1666
|
-
#zone;
|
|
1667
|
-
#template;
|
|
1668
|
-
#view;
|
|
1669
|
-
constructor() {
|
|
1670
|
-
this.#vcr = inject(ViewContainerRef);
|
|
1671
|
-
this.#zone = inject(NgZone);
|
|
1672
|
-
this.#template = inject(TemplateRef);
|
|
1673
|
-
this.injected = false;
|
|
1674
|
-
this.shouldCreateView = true;
|
|
1675
|
-
const commentNode = this.#vcr.element.nativeElement;
|
|
1676
|
-
if (commentNode[SPECIAL_INTERNAL_ADD_COMMENT]) {
|
|
1677
|
-
commentNode[SPECIAL_INTERNAL_ADD_COMMENT]();
|
|
1678
|
-
delete commentNode[SPECIAL_INTERNAL_ADD_COMMENT];
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
createView() {
|
|
1682
|
-
if (this.shouldCreateView) {
|
|
1683
|
-
if (this.#view && !this.#view.destroyed) {
|
|
1684
|
-
this.#view.destroy();
|
|
1685
|
-
}
|
|
1686
|
-
this.#zone.runOutsideAngular(() => {
|
|
1687
|
-
this.#view = this.#vcr.createEmbeddedView(this.#template);
|
|
1688
|
-
safeDetectChanges(this.#view);
|
|
1689
|
-
});
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: NgtCommonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1693
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.3", type: NgtCommonDirective, ngImport: i0 }); }
|
|
1694
|
-
}
|
|
1695
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: NgtCommonDirective, decorators: [{
|
|
1696
|
-
type: Directive
|
|
1697
|
-
}], ctorParameters: function () { return []; } });
|
|
1698
|
-
|
|
1699
|
-
class NgtArgs extends NgtCommonDirective {
|
|
1700
|
-
#injectedArgs = [];
|
|
1701
|
-
set args(args) {
|
|
1702
|
-
if (args == null || !Array.isArray(args) || (args.length === 1 && args[0] === null))
|
|
1703
|
-
return;
|
|
1704
|
-
this.injected = false;
|
|
1705
|
-
this.#injectedArgs = args;
|
|
1706
|
-
this.createView();
|
|
1707
|
-
}
|
|
1708
|
-
get args() {
|
|
1709
|
-
if (this.validate()) {
|
|
1710
|
-
this.injected = true;
|
|
1711
|
-
return this.#injectedArgs;
|
|
1712
|
-
}
|
|
1713
|
-
return null;
|
|
1714
|
-
}
|
|
1715
|
-
validate() {
|
|
1716
|
-
return !this.injected && !!this.#injectedArgs.length;
|
|
1717
|
-
}
|
|
1718
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: NgtArgs, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1719
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.3", type: NgtArgs, isStandalone: true, selector: "[args]", inputs: { args: "args" }, usesInheritance: true, ngImport: i0 }); }
|
|
1720
|
-
}
|
|
1721
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: NgtArgs, decorators: [{
|
|
1722
|
-
type: Directive,
|
|
1723
|
-
args: [{ selector: '[args]', standalone: true }]
|
|
1724
|
-
}], propDecorators: { args: [{
|
|
1725
|
-
type: Input
|
|
1726
|
-
}] } });
|
|
1727
|
-
|
|
1728
|
-
class NgtParent extends NgtCommonDirective {
|
|
1729
|
-
#injectedParent = null;
|
|
1730
|
-
set parent(parent) {
|
|
1731
|
-
if (!parent)
|
|
1732
|
-
return;
|
|
1733
|
-
this.injected = false;
|
|
1734
|
-
this.#injectedParent = parent;
|
|
1735
|
-
this.createView();
|
|
1736
|
-
}
|
|
1737
|
-
get parent() {
|
|
1738
|
-
if (this.validate()) {
|
|
1739
|
-
this.injected = true;
|
|
1740
|
-
return this.#injectedParent;
|
|
1741
|
-
}
|
|
1742
|
-
return null;
|
|
1743
|
-
}
|
|
1744
|
-
validate() {
|
|
1745
|
-
return !this.injected && !!this.#injectedParent;
|
|
1746
|
-
}
|
|
1747
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: NgtParent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1748
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.3", type: NgtParent, isStandalone: true, selector: "[parent]", inputs: { parent: "parent" }, usesInheritance: true, ngImport: i0 }); }
|
|
1749
|
-
}
|
|
1750
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: NgtParent, decorators: [{
|
|
1751
|
-
type: Directive,
|
|
1752
|
-
args: [{ selector: '[parent]', standalone: true }]
|
|
1753
|
-
}], propDecorators: { parent: [{
|
|
1754
|
-
type: Input
|
|
1755
|
-
}] } });
|
|
1756
1877
|
|
|
1878
|
+
const NGT_COMPOUND_PREFIXES = new InjectionToken('NgtCompoundPrefixes');
|
|
1757
1879
|
class NgtRendererStore {
|
|
1758
|
-
#comments = [];
|
|
1759
1880
|
constructor(root) {
|
|
1760
1881
|
this.root = root;
|
|
1882
|
+
this.comments = [];
|
|
1761
1883
|
}
|
|
1762
1884
|
createNode(type, node) {
|
|
1763
1885
|
const state = [
|
|
@@ -1778,10 +1900,10 @@ class NgtRendererStore {
|
|
|
1778
1900
|
undefined,
|
|
1779
1901
|
];
|
|
1780
1902
|
const rendererNode = Object.assign(node, { __ngt_renderer__: state });
|
|
1781
|
-
// assign ownerDocument to node so we can use HostListener in Component
|
|
1903
|
+
// NOTE: assign ownerDocument to node so we can use HostListener in Component
|
|
1782
1904
|
if (!rendererNode['ownerDocument'])
|
|
1783
1905
|
rendererNode['ownerDocument'] = this.root.document;
|
|
1784
|
-
// assign injectorFactory on non-three type since
|
|
1906
|
+
// NOTE: assign injectorFactory on non-three type since
|
|
1785
1907
|
// rendererNode is an instance of DOM Node
|
|
1786
1908
|
if (state[0 /* NgtRendererClassId.type */] !== 'three') {
|
|
1787
1909
|
state[14 /* NgtRendererClassId.injectorFactory */] = () => getDebugNode(rendererNode).injector;
|
|
@@ -1795,7 +1917,7 @@ class NgtRendererStore {
|
|
|
1795
1917
|
this.portals.push(node);
|
|
1796
1918
|
}
|
|
1797
1919
|
else {
|
|
1798
|
-
this
|
|
1920
|
+
this.comments.push(rendererNode);
|
|
1799
1921
|
}
|
|
1800
1922
|
};
|
|
1801
1923
|
return rendererNode;
|
|
@@ -1819,12 +1941,21 @@ class NgtRendererStore {
|
|
|
1819
1941
|
}
|
|
1820
1942
|
}
|
|
1821
1943
|
removeChild(node, child) {
|
|
1822
|
-
const index = node.__ngt_renderer__[3 /* NgtRendererClassId.children */].findIndex((c) => child === c);
|
|
1944
|
+
const index = node.__ngt_renderer__?.[3 /* NgtRendererClassId.children */].findIndex((c) => child === c);
|
|
1823
1945
|
if (index >= 0) {
|
|
1824
1946
|
node.__ngt_renderer__[3 /* NgtRendererClassId.children */].splice(index, 1);
|
|
1825
1947
|
}
|
|
1826
1948
|
}
|
|
1827
1949
|
setCompound(compound, instance) {
|
|
1950
|
+
const instanceRS = instance.__ngt_renderer__;
|
|
1951
|
+
if (instanceRS && instanceRS[1 /* NgtRendererClassId.parent */]) {
|
|
1952
|
+
const parentRS = instanceRS[1 /* NgtRendererClassId.parent */].__ngt_renderer__;
|
|
1953
|
+
// NOTE: if instance is already compounded by its parent. skip
|
|
1954
|
+
if (parentRS[0 /* NgtRendererClassId.type */] === 'compound' &&
|
|
1955
|
+
parentRS[7 /* NgtRendererClassId.compounded */] === instance) {
|
|
1956
|
+
return;
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1828
1959
|
const rS = compound.__ngt_renderer__;
|
|
1829
1960
|
rS[7 /* NgtRendererClassId.compounded */] = instance;
|
|
1830
1961
|
const attributes = Object.keys(rS[9 /* NgtRendererClassId.attributes */]);
|
|
@@ -1856,7 +1987,7 @@ class NgtRendererStore {
|
|
|
1856
1987
|
const injector = injectorFactory?.();
|
|
1857
1988
|
if (!injector)
|
|
1858
1989
|
return;
|
|
1859
|
-
const portalStore = injector.get(
|
|
1990
|
+
const portalStore = injector.get(NGT_STORE, null);
|
|
1860
1991
|
if (!portalStore)
|
|
1861
1992
|
return;
|
|
1862
1993
|
const portalContainer = portalStore.get('scene');
|
|
@@ -1869,8 +2000,8 @@ class NgtRendererStore {
|
|
|
1869
2000
|
if (rS[4 /* NgtRendererClassId.destroyed */])
|
|
1870
2001
|
return;
|
|
1871
2002
|
if (name === SPECIAL_PROPERTIES.RENDER_PRIORITY) {
|
|
1872
|
-
// priority needs to be set as an attribute string so that they can be set as early as possible
|
|
1873
|
-
// we convert that string to a number. if it's invalid, 0
|
|
2003
|
+
// NOTE: priority needs to be set as an attribute string so that they can be set as early as possible
|
|
2004
|
+
// we convert that string to a number. if it's invalid, default 0
|
|
1874
2005
|
let priority = Number(value);
|
|
1875
2006
|
if (isNaN(priority)) {
|
|
1876
2007
|
priority = 0;
|
|
@@ -1879,19 +2010,19 @@ class NgtRendererStore {
|
|
|
1879
2010
|
getLocalState(node).priority = priority;
|
|
1880
2011
|
}
|
|
1881
2012
|
if (name === SPECIAL_PROPERTIES.COMPOUND) {
|
|
1882
|
-
// we set the compound property on instance node now so we know that this instance is being compounded
|
|
2013
|
+
// NOTE: we set the compound property on instance node now so we know that this instance is being compounded
|
|
1883
2014
|
rS[5 /* NgtRendererClassId.compound */] = [value === '' || value === 'first', {}];
|
|
1884
2015
|
return;
|
|
1885
2016
|
}
|
|
1886
2017
|
if (name === SPECIAL_PROPERTIES.ATTACH) {
|
|
1887
|
-
// handle attach as tring
|
|
2018
|
+
// NOTE: handle attach as tring
|
|
1888
2019
|
const paths = value.split('.');
|
|
1889
2020
|
if (paths.length)
|
|
1890
2021
|
getLocalState(node).attach = paths;
|
|
1891
2022
|
return;
|
|
1892
2023
|
}
|
|
1893
2024
|
if (name === SPECIAL_PROPERTIES.VALUE) {
|
|
1894
|
-
// coercion
|
|
2025
|
+
// NOTE: coercion
|
|
1895
2026
|
let maybeCoerced = value;
|
|
1896
2027
|
if (maybeCoerced === '' || maybeCoerced === 'true' || maybeCoerced === 'false') {
|
|
1897
2028
|
maybeCoerced = maybeCoerced === 'true' || maybeCoerced === '';
|
|
@@ -1903,7 +2034,7 @@ class NgtRendererStore {
|
|
|
1903
2034
|
return;
|
|
1904
2035
|
}
|
|
1905
2036
|
applyProps(node, { [name]: value });
|
|
1906
|
-
this
|
|
2037
|
+
this.updateNativeProps(node, name, value);
|
|
1907
2038
|
}
|
|
1908
2039
|
applyProperty(node, name, value) {
|
|
1909
2040
|
const rS = node.__ngt_renderer__;
|
|
@@ -1937,7 +2068,7 @@ class NgtRendererStore {
|
|
|
1937
2068
|
value = compound[1 /* NgtCompoundClassId.props */][name];
|
|
1938
2069
|
}
|
|
1939
2070
|
applyProps(node, { [name]: value });
|
|
1940
|
-
this
|
|
2071
|
+
this.updateNativeProps(node, name, value);
|
|
1941
2072
|
}
|
|
1942
2073
|
isCompound(name) {
|
|
1943
2074
|
return this.root.compoundPrefixes.some((prefix) => name.startsWith(prefix));
|
|
@@ -1991,14 +2122,14 @@ class NgtRendererStore {
|
|
|
1991
2122
|
return null;
|
|
1992
2123
|
}
|
|
1993
2124
|
getCreationState() {
|
|
1994
|
-
const injectedArgs = this
|
|
1995
|
-
const injectedParent = this
|
|
1996
|
-
const store = this
|
|
2125
|
+
const injectedArgs = this.firstNonInjectedDirective(NgtArgs)?.args || [];
|
|
2126
|
+
const injectedParent = this.firstNonInjectedDirective(NgtParent)?.parent || null;
|
|
2127
|
+
const store = this.tryGetPortalStore();
|
|
1997
2128
|
return { injectedArgs, injectedParent, store };
|
|
1998
2129
|
}
|
|
1999
2130
|
destroy(node, parent) {
|
|
2000
2131
|
const rS = node.__ngt_renderer__;
|
|
2001
|
-
if (rS[4 /* NgtRendererClassId.destroyed */])
|
|
2132
|
+
if (!rS || rS[4 /* NgtRendererClassId.destroyed */])
|
|
2002
2133
|
return;
|
|
2003
2134
|
if (rS[0 /* NgtRendererClassId.type */] === 'three') {
|
|
2004
2135
|
rS[5 /* NgtRendererClassId.compound */] = undefined;
|
|
@@ -2030,9 +2161,9 @@ class NgtRendererStore {
|
|
|
2030
2161
|
if (rS[0 /* NgtRendererClassId.type */] === 'comment') {
|
|
2031
2162
|
rS[14 /* NgtRendererClassId.injectorFactory */] = null;
|
|
2032
2163
|
delete node[SPECIAL_INTERNAL_ADD_COMMENT];
|
|
2033
|
-
const index = this
|
|
2164
|
+
const index = this.comments.findIndex((comment) => comment === node);
|
|
2034
2165
|
if (index > -1) {
|
|
2035
|
-
this
|
|
2166
|
+
this.comments.splice(index, 1);
|
|
2036
2167
|
}
|
|
2037
2168
|
}
|
|
2038
2169
|
if (rS[0 /* NgtRendererClassId.type */] === 'portal') {
|
|
@@ -2052,13 +2183,17 @@ class NgtRendererStore {
|
|
|
2052
2183
|
}
|
|
2053
2184
|
if (rS[12 /* NgtRendererClassId.ref */]) {
|
|
2054
2185
|
// nullify ref
|
|
2055
|
-
|
|
2056
|
-
|
|
2186
|
+
// but we do it later so that it doesn't hinder render
|
|
2187
|
+
// TODO: will this cause memory leak?
|
|
2188
|
+
requestAnimationFrame(() => {
|
|
2189
|
+
rS[12 /* NgtRendererClassId.ref */].nativeElement = null;
|
|
2190
|
+
rS[12 /* NgtRendererClassId.ref */] = undefined;
|
|
2191
|
+
});
|
|
2057
2192
|
}
|
|
2058
2193
|
// nullify parent
|
|
2059
2194
|
rS[1 /* NgtRendererClassId.parent */] = null;
|
|
2060
2195
|
for (const renderChild of rS[3 /* NgtRendererClassId.children */] || []) {
|
|
2061
|
-
if (renderChild.__ngt_renderer__[0 /* NgtRendererClassId.type */] === 'three' && parent) {
|
|
2196
|
+
if (renderChild.__ngt_renderer__?.[0 /* NgtRendererClassId.type */] === 'three' && parent) {
|
|
2062
2197
|
removeThreeChild(parent, renderChild, true);
|
|
2063
2198
|
}
|
|
2064
2199
|
this.destroy(renderChild, parent);
|
|
@@ -2069,20 +2204,20 @@ class NgtRendererStore {
|
|
|
2069
2204
|
this.removeChild(parent, node);
|
|
2070
2205
|
}
|
|
2071
2206
|
}
|
|
2072
|
-
|
|
2207
|
+
updateNativeProps(node, key, value) {
|
|
2073
2208
|
const localState = getLocalState(node);
|
|
2074
2209
|
if (!localState || !localState.nativeProps)
|
|
2075
2210
|
return;
|
|
2076
|
-
|
|
2077
|
-
localState.nativeProps.set({ [name]: value });
|
|
2078
|
-
});
|
|
2211
|
+
localState.nativeProps.set({ [key]: value });
|
|
2079
2212
|
}
|
|
2080
|
-
|
|
2213
|
+
firstNonInjectedDirective(dir) {
|
|
2081
2214
|
let directive;
|
|
2082
|
-
|
|
2215
|
+
const destroyed = [];
|
|
2216
|
+
let i = this.comments.length - 1;
|
|
2083
2217
|
while (i >= 0) {
|
|
2084
|
-
const comment = this
|
|
2218
|
+
const comment = this.comments[i];
|
|
2085
2219
|
if (comment.__ngt_renderer__[4 /* NgtRendererClassId.destroyed */]) {
|
|
2220
|
+
destroyed.push(i);
|
|
2086
2221
|
i--;
|
|
2087
2222
|
continue;
|
|
2088
2223
|
}
|
|
@@ -2098,16 +2233,21 @@ class NgtRendererStore {
|
|
|
2098
2233
|
}
|
|
2099
2234
|
i--;
|
|
2100
2235
|
}
|
|
2236
|
+
destroyed.forEach((index) => {
|
|
2237
|
+
this.comments.splice(index, 1);
|
|
2238
|
+
});
|
|
2101
2239
|
return directive;
|
|
2102
2240
|
}
|
|
2103
|
-
|
|
2241
|
+
tryGetPortalStore() {
|
|
2104
2242
|
let store;
|
|
2243
|
+
const destroyed = [];
|
|
2105
2244
|
// we only care about the portal states because NgtStore only differs per Portal
|
|
2106
2245
|
let i = this.portals.length - 1;
|
|
2107
2246
|
while (i >= 0) {
|
|
2108
2247
|
// loop through the portal state backwards to find the closest NgtStore
|
|
2109
2248
|
const portal = this.portals[i];
|
|
2110
2249
|
if (portal.__ngt_renderer__[4 /* NgtRendererClassId.destroyed */]) {
|
|
2250
|
+
destroyed.push(i);
|
|
2111
2251
|
i--;
|
|
2112
2252
|
continue;
|
|
2113
2253
|
}
|
|
@@ -2116,55 +2256,62 @@ class NgtRendererStore {
|
|
|
2116
2256
|
i--;
|
|
2117
2257
|
continue;
|
|
2118
2258
|
}
|
|
2119
|
-
const instance = injector.get(
|
|
2120
|
-
// only the instance with
|
|
2121
|
-
if (instance && instance.get('
|
|
2259
|
+
const instance = injector.get(NGT_STORE, null);
|
|
2260
|
+
// only the instance with previousRoot should pass
|
|
2261
|
+
if (instance && instance.get('previousRoot')) {
|
|
2122
2262
|
store = instance;
|
|
2123
2263
|
break;
|
|
2124
2264
|
}
|
|
2125
2265
|
i--;
|
|
2126
2266
|
}
|
|
2267
|
+
destroyed.forEach((index) => {
|
|
2268
|
+
this.portals.splice(index, 1);
|
|
2269
|
+
});
|
|
2127
2270
|
return store || this.root.store;
|
|
2128
2271
|
}
|
|
2129
2272
|
}
|
|
2130
2273
|
|
|
2131
2274
|
class NgtRendererFactory {
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2275
|
+
constructor() {
|
|
2276
|
+
this.delegateRendererFactory = inject(RendererFactory2, { skipSelf: true });
|
|
2277
|
+
this.zone = inject(NgZone);
|
|
2278
|
+
this.catalogue = injectNgtCatalogue();
|
|
2279
|
+
this.cdr = inject(ChangeDetectorRef);
|
|
2280
|
+
this.rendererMap = new Map();
|
|
2281
|
+
this.routedSet = new Set();
|
|
2282
|
+
// all Renderer instances share the same Store
|
|
2283
|
+
this.rendererStore = new NgtRendererStore({
|
|
2284
|
+
portals: [],
|
|
2285
|
+
store: injectNgtStore(),
|
|
2286
|
+
compoundPrefixes: inject(NGT_COMPOUND_PREFIXES),
|
|
2287
|
+
document: inject(DOCUMENT),
|
|
2288
|
+
});
|
|
2289
|
+
}
|
|
2145
2290
|
createRenderer(hostElement, type) {
|
|
2146
|
-
const
|
|
2291
|
+
const delegate = this.delegateRendererFactory.createRenderer(hostElement, type);
|
|
2147
2292
|
if (!type)
|
|
2148
|
-
return
|
|
2149
|
-
//
|
|
2150
|
-
|
|
2151
|
-
|
|
2293
|
+
return delegate;
|
|
2294
|
+
// TODO: handle html in canvas
|
|
2295
|
+
if (type['type'][HTML]) {
|
|
2296
|
+
this.rendererMap.set(type.id, delegate);
|
|
2297
|
+
return delegate;
|
|
2298
|
+
}
|
|
2152
2299
|
if (type['type'][ROUTED_SCENE]) {
|
|
2153
|
-
this
|
|
2300
|
+
this.routedSet.add(type.id);
|
|
2154
2301
|
}
|
|
2155
|
-
let renderer = this
|
|
2302
|
+
let renderer = this.rendererMap.get(type.id);
|
|
2156
2303
|
if (!renderer) {
|
|
2157
|
-
renderer = new NgtRenderer(
|
|
2304
|
+
renderer = new NgtRenderer(delegate, this.rendererStore, this.catalogue, this.zone, this.cdr,
|
|
2158
2305
|
// setting root scene if there's no routed scene OR this component is the routed Scene
|
|
2159
|
-
!hostElement && (this
|
|
2160
|
-
this
|
|
2306
|
+
!hostElement && (this.routedSet.size === 0 || this.routedSet.has(type.id)));
|
|
2307
|
+
this.rendererMap.set(type.id, renderer);
|
|
2161
2308
|
}
|
|
2162
2309
|
return renderer;
|
|
2163
2310
|
}
|
|
2164
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
2165
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.
|
|
2311
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtRendererFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2312
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtRendererFactory }); }
|
|
2166
2313
|
}
|
|
2167
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
2314
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtRendererFactory, decorators: [{
|
|
2168
2315
|
type: Injectable
|
|
2169
2316
|
}] });
|
|
2170
2317
|
/**
|
|
@@ -2265,16 +2412,19 @@ class NgtRenderer {
|
|
|
2265
2412
|
return this.store.createNode('comment', this.delegate.createComment(value));
|
|
2266
2413
|
}
|
|
2267
2414
|
appendChild(parent, newChild) {
|
|
2268
|
-
// TODO: just ignore text node for now
|
|
2269
|
-
if (newChild instanceof Text)
|
|
2270
|
-
return;
|
|
2271
|
-
const cRS = newChild.__ngt_renderer__;
|
|
2272
2415
|
const pRS = parent.__ngt_renderer__;
|
|
2273
|
-
|
|
2416
|
+
const cRS = newChild.__ngt_renderer__;
|
|
2417
|
+
if (pRS[0 /* NgtRendererClassId.type */] === 'dom' &&
|
|
2418
|
+
(newChild instanceof Text || cRS[0 /* NgtRendererClassId.type */] === 'dom')) {
|
|
2419
|
+
this.store.addChild(parent, newChild);
|
|
2420
|
+
this.delegate.appendChild(parent, newChild);
|
|
2421
|
+
return;
|
|
2422
|
+
}
|
|
2423
|
+
if (cRS?.[0 /* NgtRendererClassId.type */] === 'comment') {
|
|
2274
2424
|
this.store.setParent(newChild, parent);
|
|
2275
2425
|
return;
|
|
2276
2426
|
}
|
|
2277
|
-
if (cRS[2 /* NgtRendererClassId.injectedParent */]) {
|
|
2427
|
+
if (cRS?.[2 /* NgtRendererClassId.injectedParent */]) {
|
|
2278
2428
|
if (is.ref(cRS[2 /* NgtRendererClassId.injectedParent */])) {
|
|
2279
2429
|
const injector = cRS[14 /* NgtRendererClassId.injectorFactory */]().get(Injector, null);
|
|
2280
2430
|
if (!injector) {
|
|
@@ -2300,7 +2450,7 @@ class NgtRenderer {
|
|
|
2300
2450
|
this.store.setParent(newChild, parent);
|
|
2301
2451
|
this.store.addChild(parent, newChild);
|
|
2302
2452
|
// if new child is a portal
|
|
2303
|
-
if (cRS[0 /* NgtRendererClassId.type */] === 'portal') {
|
|
2453
|
+
if (cRS?.[0 /* NgtRendererClassId.type */] === 'portal') {
|
|
2304
2454
|
this.store.processPortalContainer(newChild);
|
|
2305
2455
|
if (cRS[13 /* NgtRendererClassId.portalContainer */]) {
|
|
2306
2456
|
this.appendChild(parent, cRS[13 /* NgtRendererClassId.portalContainer */]);
|
|
@@ -2316,7 +2466,7 @@ class NgtRenderer {
|
|
|
2316
2466
|
return;
|
|
2317
2467
|
}
|
|
2318
2468
|
// if both are three instances, straightforward case
|
|
2319
|
-
if (pRS[0 /* NgtRendererClassId.type */] === 'three' && cRS[0 /* NgtRendererClassId.type */] === 'three') {
|
|
2469
|
+
if (pRS[0 /* NgtRendererClassId.type */] === 'three' && cRS?.[0 /* NgtRendererClassId.type */] === 'three') {
|
|
2320
2470
|
// if child already attached to a parent, skip
|
|
2321
2471
|
if (getLocalState(newChild).parent && untracked(getLocalState(newChild).parent))
|
|
2322
2472
|
return;
|
|
@@ -2333,7 +2483,7 @@ class NgtRenderer {
|
|
|
2333
2483
|
}
|
|
2334
2484
|
// if only the parent is the THREE instance
|
|
2335
2485
|
if (pRS[0 /* NgtRendererClassId.type */] === 'three') {
|
|
2336
|
-
for (const renderChild of cRS[3 /* NgtRendererClassId.children */]) {
|
|
2486
|
+
for (const renderChild of cRS?.[3 /* NgtRendererClassId.children */]) {
|
|
2337
2487
|
this.appendChild(parent, renderChild);
|
|
2338
2488
|
}
|
|
2339
2489
|
}
|
|
@@ -2356,27 +2506,15 @@ class NgtRenderer {
|
|
|
2356
2506
|
this.store.setCompound(parent, newChild);
|
|
2357
2507
|
}
|
|
2358
2508
|
}
|
|
2359
|
-
|
|
2360
|
-
// if child is three but haven't been attached to a parent yet
|
|
2361
|
-
(cRS[0 /* NgtRendererClassId.type */] === 'three' && !untracked(getLocalState(newChild).parent)) ||
|
|
2362
|
-
// or both parent and child are DOM elements
|
|
2363
|
-
// or they are compound AND haven't had a THREE instance yet
|
|
2364
|
-
((pRS[0 /* NgtRendererClassId.type */] === 'dom' ||
|
|
2365
|
-
(pRS[0 /* NgtRendererClassId.type */] === 'compound' && !pRS[7 /* NgtRendererClassId.compounded */])) &&
|
|
2366
|
-
(cRS[0 /* NgtRendererClassId.type */] === 'dom' ||
|
|
2367
|
-
(cRS[0 /* NgtRendererClassId.type */] === 'compound' && !cRS[7 /* NgtRendererClassId.compounded */])));
|
|
2368
|
-
if (shouldFindGrandparentInstance) {
|
|
2509
|
+
if (this.shouldFindGrandparentInstance(pRS, cRS, newChild)) {
|
|
2369
2510
|
// we'll try to get the grandparent instance here so that we can run appendChild with both instances
|
|
2370
2511
|
const closestGrandparentInstance = this.store.getClosestParentWithInstance(parent);
|
|
2371
2512
|
if (closestGrandparentInstance)
|
|
2372
2513
|
this.appendChild(closestGrandparentInstance, newChild);
|
|
2514
|
+
return;
|
|
2373
2515
|
}
|
|
2374
2516
|
}
|
|
2375
|
-
insertBefore(parent, newChild
|
|
2376
|
-
// TODO: we might need these?
|
|
2377
|
-
// refChild: NgtRendererNode
|
|
2378
|
-
// isMove?: boolean | undefined
|
|
2379
|
-
) {
|
|
2517
|
+
insertBefore(parent, newChild) {
|
|
2380
2518
|
if (parent == null || !parent.__ngt_renderer__ || parent === newChild)
|
|
2381
2519
|
return;
|
|
2382
2520
|
this.appendChild(parent, newChild);
|
|
@@ -2384,6 +2522,18 @@ class NgtRenderer {
|
|
|
2384
2522
|
removeChild(parent, oldChild, isHostElement) {
|
|
2385
2523
|
const pRS = parent.__ngt_renderer__;
|
|
2386
2524
|
const cRS = oldChild.__ngt_renderer__;
|
|
2525
|
+
if ((!cRS || !pRS) &&
|
|
2526
|
+
parent instanceof Element &&
|
|
2527
|
+
(oldChild instanceof Element || oldChild instanceof Text || oldChild instanceof Comment)) {
|
|
2528
|
+
this.delegate.removeChild(parent, oldChild);
|
|
2529
|
+
this.store.destroy(oldChild, parent);
|
|
2530
|
+
return;
|
|
2531
|
+
}
|
|
2532
|
+
if (cRS[0 /* NgtRendererClassId.type */] === 'dom' && (!pRS || pRS[0 /* NgtRendererClassId.type */] === 'dom')) {
|
|
2533
|
+
this.delegate.removeChild(parent, oldChild);
|
|
2534
|
+
this.store.destroy(oldChild, parent);
|
|
2535
|
+
return;
|
|
2536
|
+
}
|
|
2387
2537
|
if (pRS[0 /* NgtRendererClassId.type */] === 'three' && cRS[0 /* NgtRendererClassId.type */] === 'three') {
|
|
2388
2538
|
removeThreeChild(parent, oldChild, true);
|
|
2389
2539
|
this.store.destroy(oldChild, parent);
|
|
@@ -2420,8 +2570,11 @@ class NgtRenderer {
|
|
|
2420
2570
|
this.setAttribute(rS[7 /* NgtRendererClassId.compounded */], name, value, namespace);
|
|
2421
2571
|
return;
|
|
2422
2572
|
}
|
|
2423
|
-
if (rS[0 /* NgtRendererClassId.type */] === 'three')
|
|
2573
|
+
if (rS[0 /* NgtRendererClassId.type */] === 'three') {
|
|
2424
2574
|
this.store.applyAttribute(el, name, value);
|
|
2575
|
+
return;
|
|
2576
|
+
}
|
|
2577
|
+
return this.delegate.setAttribute(el, name, value);
|
|
2425
2578
|
}
|
|
2426
2579
|
setProperty(el, name, value) {
|
|
2427
2580
|
const rS = el.__ngt_renderer__;
|
|
@@ -2433,15 +2586,16 @@ class NgtRenderer {
|
|
|
2433
2586
|
return;
|
|
2434
2587
|
}
|
|
2435
2588
|
if (rS[7 /* NgtRendererClassId.compounded */].__ngt_renderer__[5 /* NgtRendererClassId.compound */]) {
|
|
2436
|
-
Object.assign(rS[7 /* NgtRendererClassId.compounded */].__ngt_renderer__[5 /* NgtRendererClassId.compound */], {
|
|
2437
|
-
props: Object.assign(rS[7 /* NgtRendererClassId.compounded */].__ngt_renderer__[5 /* NgtRendererClassId.compound */], { [name]: value }),
|
|
2438
|
-
});
|
|
2589
|
+
Object.assign(rS[7 /* NgtRendererClassId.compounded */].__ngt_renderer__[5 /* NgtRendererClassId.compound */][1 /* NgtCompoundClassId.props */], { [name]: value });
|
|
2439
2590
|
}
|
|
2440
2591
|
this.setProperty(rS[7 /* NgtRendererClassId.compounded */], name, value);
|
|
2441
2592
|
return;
|
|
2442
2593
|
}
|
|
2443
|
-
if (rS[0 /* NgtRendererClassId.type */] === 'three')
|
|
2594
|
+
if (rS[0 /* NgtRendererClassId.type */] === 'three') {
|
|
2444
2595
|
this.store.applyProperty(el, name, value);
|
|
2596
|
+
return;
|
|
2597
|
+
}
|
|
2598
|
+
return this.delegate.setProperty(el, name, value);
|
|
2445
2599
|
}
|
|
2446
2600
|
listen(target, eventName, callback) {
|
|
2447
2601
|
const rS = target.__ngt_renderer__;
|
|
@@ -2479,171 +2633,165 @@ class NgtRenderer {
|
|
|
2479
2633
|
}
|
|
2480
2634
|
return () => { };
|
|
2481
2635
|
}
|
|
2636
|
+
shouldFindGrandparentInstance(pRS, cRS, child) {
|
|
2637
|
+
const pType = pRS[0 /* NgtRendererClassId.type */];
|
|
2638
|
+
const cType = cRS[0 /* NgtRendererClassId.type */];
|
|
2639
|
+
const isParentCompounded = pRS[7 /* NgtRendererClassId.compounded */];
|
|
2640
|
+
const isChildCompounded = cRS[7 /* NgtRendererClassId.compounded */];
|
|
2641
|
+
// if child is three but haven't been attached to a parent yet
|
|
2642
|
+
const isDanglingThreeChild = cType === 'three' && !untracked(getLocalState(child).parent);
|
|
2643
|
+
// or both parent and child are DOM elements
|
|
2644
|
+
// or they are compound AND haven't had a THREE instance yet
|
|
2645
|
+
const isParentStillDOM = pType === 'dom' || (pType === 'compound' && !isParentCompounded);
|
|
2646
|
+
const isChildStillDOM = cType === 'dom' || (cType === 'compound' && !isChildCompounded);
|
|
2647
|
+
// and the child is a compounded compound
|
|
2648
|
+
const isCompoundChildCompounded = cType === 'compound' && !!isChildCompounded;
|
|
2649
|
+
return (isDanglingThreeChild ||
|
|
2650
|
+
(isParentStillDOM && isChildStillDOM) ||
|
|
2651
|
+
(isParentStillDOM && isCompoundChildCompounded));
|
|
2652
|
+
}
|
|
2482
2653
|
get data() {
|
|
2483
2654
|
return this.delegate.data;
|
|
2484
2655
|
}
|
|
2485
2656
|
}
|
|
2486
|
-
|
|
2487
|
-
function provideNgtRenderer({ store, changeDetectorRef, compoundPrefixes = [] }) {
|
|
2657
|
+
function provideNgtRenderer(store, compoundPrefixes, cdr) {
|
|
2488
2658
|
if (!compoundPrefixes.includes('ngts'))
|
|
2489
2659
|
compoundPrefixes.push('ngts');
|
|
2490
2660
|
if (!compoundPrefixes.includes('ngtp'))
|
|
2491
2661
|
compoundPrefixes.push('ngtp');
|
|
2492
2662
|
return makeEnvironmentProviders([
|
|
2493
2663
|
{ provide: RendererFactory2, useClass: NgtRendererFactory },
|
|
2494
|
-
{ provide: NgtStore, useValue: store },
|
|
2495
|
-
{ provide: ChangeDetectorRef, useValue: changeDetectorRef },
|
|
2496
2664
|
{ provide: NGT_COMPOUND_PREFIXES, useValue: compoundPrefixes },
|
|
2665
|
+
{ provide: ChangeDetectorRef, useValue: cdr },
|
|
2666
|
+
provideNgtStore(store),
|
|
2497
2667
|
provideZoneChangeDetection({ runCoalescing: true, eventCoalescing: true }),
|
|
2498
2668
|
]);
|
|
2499
2669
|
}
|
|
2500
2670
|
|
|
2501
|
-
class NgtCanvas
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2671
|
+
class NgtCanvas {
|
|
2672
|
+
constructor() {
|
|
2673
|
+
this.store = injectNgtStore();
|
|
2674
|
+
this.initRoot = injectCanvasRootInitializer();
|
|
2675
|
+
this.host = inject(ElementRef);
|
|
2676
|
+
this.viewContainerRef = inject(ViewContainerRef);
|
|
2677
|
+
this.injector = inject(Injector);
|
|
2678
|
+
this.environmentInjector = inject(EnvironmentInjector);
|
|
2679
|
+
this.zone = inject(NgZone);
|
|
2680
|
+
this.destroyRef = inject(DestroyRef);
|
|
2681
|
+
this.cdr = inject(ChangeDetectorRef);
|
|
2682
|
+
this.inputs = signalStore({
|
|
2683
|
+
shadows: false,
|
|
2684
|
+
linear: false,
|
|
2685
|
+
flat: false,
|
|
2686
|
+
legacy: false,
|
|
2687
|
+
orthographic: false,
|
|
2688
|
+
frameloop: 'always',
|
|
2689
|
+
dpr: [1, 2],
|
|
2690
|
+
events: createPointerEvents,
|
|
2691
|
+
});
|
|
2692
|
+
this.sceneGraphInputs = {};
|
|
2693
|
+
this.compoundPrefixes = [];
|
|
2694
|
+
this.created = new EventEmitter();
|
|
2695
|
+
this.inputsEventSource = this.inputs.select('eventSource');
|
|
2696
|
+
this.hbPointerEvents = computed(() => (!!this.inputsEventSource() ? 'none' : 'auto'));
|
|
2697
|
+
}
|
|
2509
2698
|
set linear(linear) {
|
|
2510
|
-
this.set({ linear });
|
|
2699
|
+
this.inputs.set({ linear });
|
|
2511
2700
|
}
|
|
2512
2701
|
set legacy(legacy) {
|
|
2513
|
-
this.set({ legacy });
|
|
2702
|
+
this.inputs.set({ legacy });
|
|
2514
2703
|
}
|
|
2515
2704
|
set flat(flat) {
|
|
2516
|
-
this.set({ flat });
|
|
2705
|
+
this.inputs.set({ flat });
|
|
2517
2706
|
}
|
|
2518
2707
|
set orthographic(orthographic) {
|
|
2519
|
-
this.set({ orthographic });
|
|
2708
|
+
this.inputs.set({ orthographic });
|
|
2520
2709
|
}
|
|
2521
2710
|
set frameloop(frameloop) {
|
|
2522
|
-
this.set({ frameloop });
|
|
2711
|
+
this.inputs.set({ frameloop });
|
|
2523
2712
|
}
|
|
2524
2713
|
set dpr(dpr) {
|
|
2525
|
-
this.set({ dpr });
|
|
2714
|
+
this.inputs.set({ dpr });
|
|
2526
2715
|
}
|
|
2527
2716
|
set raycaster(raycaster) {
|
|
2528
|
-
this.set({ raycaster });
|
|
2717
|
+
this.inputs.set({ raycaster });
|
|
2529
2718
|
}
|
|
2530
2719
|
set shadows(shadows) {
|
|
2531
|
-
this.set({ shadows });
|
|
2720
|
+
this.inputs.set({ shadows });
|
|
2532
2721
|
}
|
|
2533
2722
|
set camera(camera) {
|
|
2534
|
-
this.set({ camera });
|
|
2723
|
+
this.inputs.set({ camera });
|
|
2535
2724
|
}
|
|
2536
2725
|
set scene(scene) {
|
|
2537
|
-
this.set({ scene });
|
|
2726
|
+
this.inputs.set({ scene });
|
|
2538
2727
|
}
|
|
2539
2728
|
set gl(gl) {
|
|
2540
|
-
this.set({ gl });
|
|
2729
|
+
this.inputs.set({ gl });
|
|
2541
2730
|
}
|
|
2542
2731
|
set eventSource(eventSource) {
|
|
2543
|
-
this.set({ eventSource });
|
|
2732
|
+
this.inputs.set({ eventSource });
|
|
2544
2733
|
}
|
|
2545
2734
|
set eventPrefix(eventPrefix) {
|
|
2546
|
-
this.set({ eventPrefix });
|
|
2735
|
+
this.inputs.set({ eventPrefix });
|
|
2547
2736
|
}
|
|
2548
2737
|
set lookAt(lookAt) {
|
|
2549
|
-
this.set({ lookAt });
|
|
2738
|
+
this.inputs.set({ lookAt });
|
|
2550
2739
|
}
|
|
2551
2740
|
set performance(performance) {
|
|
2552
|
-
this.set({ performance });
|
|
2553
|
-
}
|
|
2554
|
-
#glRef;
|
|
2555
|
-
#glEnvInjector;
|
|
2556
|
-
constructor() {
|
|
2557
|
-
super({
|
|
2558
|
-
shadows: false,
|
|
2559
|
-
linear: false,
|
|
2560
|
-
flat: false,
|
|
2561
|
-
legacy: false,
|
|
2562
|
-
orthographic: false,
|
|
2563
|
-
frameloop: 'always',
|
|
2564
|
-
dpr: [1, 2],
|
|
2565
|
-
events: createPointerEvents,
|
|
2566
|
-
});
|
|
2567
|
-
this.#envInjector = inject(EnvironmentInjector);
|
|
2568
|
-
this.#injector = inject(Injector);
|
|
2569
|
-
this.#host = inject(ElementRef);
|
|
2570
|
-
this.#zone = inject(NgZone);
|
|
2571
|
-
this.#cdr = inject(ChangeDetectorRef);
|
|
2572
|
-
this.#store = inject(NgtStore);
|
|
2573
|
-
this.#isReady = this.#store.select('ready');
|
|
2574
|
-
this.sceneGraphInputs = {};
|
|
2575
|
-
this.compoundPrefixes = [];
|
|
2576
|
-
this.created = new EventEmitter();
|
|
2577
|
-
this.pointerMissed = new EventEmitter();
|
|
2578
|
-
inject(DestroyRef).onDestroy(() => {
|
|
2579
|
-
if (this.#glRef)
|
|
2580
|
-
this.#glRef.destroy();
|
|
2581
|
-
if (this.#glEnvInjector)
|
|
2582
|
-
this.#glEnvInjector.destroy();
|
|
2583
|
-
injectNgtLoader.destroy();
|
|
2584
|
-
this.#store.destroy(this.glCanvas.nativeElement);
|
|
2585
|
-
});
|
|
2586
|
-
}
|
|
2587
|
-
get hbPointerEvents() {
|
|
2588
|
-
return this.select('eventSource')() !== this.#host.nativeElement ? 'none' : 'auto';
|
|
2741
|
+
this.inputs.set({ performance });
|
|
2589
2742
|
}
|
|
2590
2743
|
ngOnChanges(changes) {
|
|
2591
|
-
if (changes['sceneGraphInputs'] && !changes['sceneGraphInputs'].firstChange && this
|
|
2592
|
-
this
|
|
2744
|
+
if (changes['sceneGraphInputs'] && !changes['sceneGraphInputs'].firstChange && this.glRef) {
|
|
2745
|
+
this.setSceneGraphInputs();
|
|
2593
2746
|
}
|
|
2594
2747
|
}
|
|
2595
2748
|
ngOnInit() {
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
this
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
if (this.#resizeRef) {
|
|
2625
|
-
this.#resizeRef.destroy();
|
|
2626
|
-
}
|
|
2627
|
-
if (width > 0 && height > 0) {
|
|
2628
|
-
if (!this.#store.isInit)
|
|
2629
|
-
this.#store.init();
|
|
2630
|
-
this.#resizeRef = this.#zone.run(() => effect(() => {
|
|
2631
|
-
const canvasInputs = this.state();
|
|
2632
|
-
this.#zone.runOutsideAngular(() => {
|
|
2633
|
-
this.#store.configure({ ...canvasInputs, size: { width, height, top, left } }, this.glCanvas.nativeElement);
|
|
2749
|
+
// NOTE: we resolve glCanvas at this point, setup the configurator
|
|
2750
|
+
this.configurator = this.initRoot(this.glCanvas.nativeElement);
|
|
2751
|
+
this.destroyRef.onDestroy(() => {
|
|
2752
|
+
this.glEnvironmentInjector?.destroy();
|
|
2753
|
+
this.glRef?.destroy();
|
|
2754
|
+
this.resizeEffectRef?.destroy();
|
|
2755
|
+
injectNgtLoader.destroy();
|
|
2756
|
+
this.configurator?.destroy();
|
|
2757
|
+
});
|
|
2758
|
+
}
|
|
2759
|
+
// NOTE: runs outside of Zone due to emitInZone: false
|
|
2760
|
+
onResize(result) {
|
|
2761
|
+
if (result.width > 0 && result.height > 0) {
|
|
2762
|
+
this.resizeEffectRef?.destroy();
|
|
2763
|
+
const inputs = this.inputs.select();
|
|
2764
|
+
// NOTE: go back into zone so that effect runs
|
|
2765
|
+
// TODO: Double-check when effect is made not depended on zone
|
|
2766
|
+
this.resizeEffectRef = this.zone.run(() => effect(() => {
|
|
2767
|
+
this.zone.runOutsideAngular(() => {
|
|
2768
|
+
if (!this.configurator)
|
|
2769
|
+
this.configurator = this.initRoot(this.glCanvas.nativeElement);
|
|
2770
|
+
this.configurator.configure({ ...inputs(), size: result });
|
|
2771
|
+
if (this.glRef) {
|
|
2772
|
+
this.cdr.detectChanges();
|
|
2773
|
+
}
|
|
2774
|
+
else {
|
|
2775
|
+
this.render();
|
|
2776
|
+
}
|
|
2634
2777
|
});
|
|
2635
|
-
}, {
|
|
2778
|
+
}, { manualCleanup: true, injector: this.injector }));
|
|
2636
2779
|
}
|
|
2637
2780
|
}
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
const
|
|
2781
|
+
render() {
|
|
2782
|
+
this.glEnvironmentInjector?.destroy();
|
|
2783
|
+
this.glRef?.destroy();
|
|
2784
|
+
// Flag the canvas active, rendering will now begin
|
|
2785
|
+
this.store.set((state) => ({ internal: { ...state.internal, active: true } }));
|
|
2786
|
+
const inputs = this.inputs.get();
|
|
2787
|
+
const state = this.store.get();
|
|
2644
2788
|
// connect to event source
|
|
2645
|
-
state.events.connect?.(
|
|
2646
|
-
|
|
2789
|
+
state.events.connect?.(inputs.eventSource
|
|
2790
|
+
? is.ref(inputs.eventSource)
|
|
2791
|
+
? inputs.eventSource.nativeElement
|
|
2792
|
+
: inputs.eventSource
|
|
2793
|
+
: this.host.nativeElement);
|
|
2794
|
+
// setup compute for eventPrefix
|
|
2647
2795
|
if (inputs.eventPrefix) {
|
|
2648
2796
|
state.setEvents({
|
|
2649
2797
|
compute: (event, store) => {
|
|
@@ -2657,70 +2805,65 @@ class NgtCanvas extends NgtSignalStore {
|
|
|
2657
2805
|
}
|
|
2658
2806
|
// emit created event if observed
|
|
2659
2807
|
if (this.created.observed) {
|
|
2660
|
-
// but go back into zone to
|
|
2661
|
-
this
|
|
2662
|
-
this.created.emit(this
|
|
2808
|
+
// but go back into zone to do so
|
|
2809
|
+
this.zone.run(() => {
|
|
2810
|
+
this.created.emit(this.store.get());
|
|
2663
2811
|
});
|
|
2664
2812
|
}
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
changeDetectorRef: this.#cdr,
|
|
2673
|
-
compoundPrefixes: this.compoundPrefixes,
|
|
2674
|
-
}),
|
|
2675
|
-
], this.#envInjector);
|
|
2676
|
-
this.#glRef = this.glAnchor.createComponent(this.sceneGraph, {
|
|
2677
|
-
environmentInjector: this.#glEnvInjector,
|
|
2678
|
-
});
|
|
2679
|
-
this.#setSceneGraphInputs();
|
|
2680
|
-
this.#overrideChangeDetectorRef();
|
|
2681
|
-
safeDetectChanges(this.#cdr);
|
|
2813
|
+
if (!this.store.get('events', 'connected')) {
|
|
2814
|
+
this.store.get('events').connect?.(this.glCanvas.nativeElement);
|
|
2815
|
+
}
|
|
2816
|
+
this.glEnvironmentInjector = createEnvironmentInjector([provideNgtRenderer(this.store, this.compoundPrefixes, this.cdr)], this.environmentInjector);
|
|
2817
|
+
this.glRef = this.viewContainerRef.createComponent(this.sceneGraph, {
|
|
2818
|
+
environmentInjector: this.glEnvironmentInjector,
|
|
2819
|
+
injector: this.injector,
|
|
2682
2820
|
});
|
|
2821
|
+
this.overrideChangeDetectorRef();
|
|
2822
|
+
this.setSceneGraphInputs();
|
|
2683
2823
|
}
|
|
2684
|
-
|
|
2685
|
-
const originalDetectChanges = this
|
|
2686
|
-
this
|
|
2824
|
+
overrideChangeDetectorRef() {
|
|
2825
|
+
const originalDetectChanges = this.cdr.detectChanges.bind(this.cdr);
|
|
2826
|
+
this.cdr.detectChanges = () => {
|
|
2687
2827
|
originalDetectChanges();
|
|
2688
|
-
safeDetectChanges(this
|
|
2828
|
+
safeDetectChanges(this.glRef?.changeDetectorRef);
|
|
2689
2829
|
};
|
|
2690
2830
|
}
|
|
2691
|
-
|
|
2692
|
-
this
|
|
2693
|
-
if (this
|
|
2831
|
+
setSceneGraphInputs() {
|
|
2832
|
+
this.zone.run(() => {
|
|
2833
|
+
if (this.glRef) {
|
|
2694
2834
|
for (const [key, value] of Object.entries(this.sceneGraphInputs)) {
|
|
2695
|
-
this
|
|
2835
|
+
this.glRef.setInput(key, value);
|
|
2696
2836
|
}
|
|
2697
|
-
|
|
2837
|
+
this.glRef.changeDetectorRef.detectChanges();
|
|
2698
2838
|
}
|
|
2699
2839
|
});
|
|
2700
2840
|
}
|
|
2701
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
2702
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2841
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtCanvas, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2842
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.7", 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" }, host: { properties: { "style.pointerEvents": "hbPointerEvents()" }, styleAttribute: "display: block;position: relative;width: 100%;height: 100%;overflow: hidden;" }, providers: [provideNgxResizeOptions({ emitInZone: false, emitInitialResult: true }), provideNgtStore()], viewQueries: [{ propertyName: "glCanvas", first: true, predicate: ["glCanvas"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
2843
|
+
<div (ngxResize)="onResize($event)" style="height: 100%; width: 100%;">
|
|
2844
|
+
<canvas #glCanvas style="display: block;"> </canvas>
|
|
2845
|
+
</div>
|
|
2846
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgxResize, selector: "[ngxResize]", inputs: ["ngxResizeOptions"], outputs: ["ngxResize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2707
2847
|
}
|
|
2708
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
2848
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtCanvas, decorators: [{
|
|
2709
2849
|
type: Component,
|
|
2710
2850
|
args: [{
|
|
2711
2851
|
selector: 'ngt-canvas',
|
|
2712
2852
|
standalone: true,
|
|
2713
2853
|
template: `
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2854
|
+
<div (ngxResize)="onResize($event)" style="height: 100%; width: 100%;">
|
|
2855
|
+
<canvas #glCanvas style="display: block;"> </canvas>
|
|
2856
|
+
</div>
|
|
2857
|
+
`,
|
|
2718
2858
|
imports: [NgxResize],
|
|
2719
|
-
providers: [
|
|
2720
|
-
host: {
|
|
2859
|
+
providers: [provideNgxResizeOptions({ emitInZone: false, emitInitialResult: true }), provideNgtStore()],
|
|
2860
|
+
host: {
|
|
2861
|
+
style: 'display: block;position: relative;width: 100%;height: 100%;overflow: hidden;',
|
|
2862
|
+
'[style.pointerEvents]': 'hbPointerEvents()',
|
|
2863
|
+
},
|
|
2721
2864
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2722
2865
|
}]
|
|
2723
|
-
}],
|
|
2866
|
+
}], propDecorators: { sceneGraph: [{
|
|
2724
2867
|
type: Input,
|
|
2725
2868
|
args: [{ required: true }]
|
|
2726
2869
|
}], sceneGraphInputs: [{
|
|
@@ -2759,34 +2902,58 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImpor
|
|
|
2759
2902
|
type: Input
|
|
2760
2903
|
}], created: [{
|
|
2761
2904
|
type: Output
|
|
2762
|
-
}], pointerMissed: [{
|
|
2763
|
-
type: Output
|
|
2764
2905
|
}], glCanvas: [{
|
|
2765
2906
|
type: ViewChild,
|
|
2766
2907
|
args: ['glCanvas', { static: true }]
|
|
2767
|
-
}], glAnchor: [{
|
|
2768
|
-
type: ViewChild,
|
|
2769
|
-
args: ['glCanvas', { static: true, read: ViewContainerRef }]
|
|
2770
2908
|
}] } });
|
|
2771
2909
|
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2910
|
+
class NgtKey extends NgtCommonDirective {
|
|
2911
|
+
constructor() {
|
|
2912
|
+
super(...arguments);
|
|
2913
|
+
this.lastKey = '';
|
|
2914
|
+
}
|
|
2915
|
+
static { this.processComment = false; }
|
|
2916
|
+
validate() {
|
|
2917
|
+
return false;
|
|
2918
|
+
}
|
|
2919
|
+
set key(key) {
|
|
2920
|
+
const normalizedKey = JSON.stringify(key);
|
|
2921
|
+
if (this.lastKey !== normalizedKey) {
|
|
2922
|
+
this.lastKey = normalizedKey;
|
|
2923
|
+
this.createView();
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtKey, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2927
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.1.7", type: NgtKey, isStandalone: true, selector: "ng-template[key]", inputs: { key: "key" }, usesInheritance: true, ngImport: i0 }); }
|
|
2928
|
+
}
|
|
2929
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtKey, decorators: [{
|
|
2930
|
+
type: Directive,
|
|
2931
|
+
args: [{ selector: 'ng-template[key]', standalone: true }]
|
|
2932
|
+
}], propDecorators: { key: [{
|
|
2933
|
+
type: Input
|
|
2934
|
+
}] } });
|
|
2935
|
+
|
|
2936
|
+
class NgtRepeat extends NgForOf {
|
|
2937
|
+
set ngForRepeat(count) {
|
|
2938
|
+
this.ngForOf = Number.isInteger(count) ? Array.from({ length: count }, (_, i) => i) : [];
|
|
2939
|
+
}
|
|
2940
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtRepeat, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2941
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.1.7", type: NgtRepeat, isStandalone: true, selector: "[ngFor][ngForRepeat]", inputs: { ngForRepeat: "ngForRepeat" }, usesInheritance: true, ngImport: i0 }); }
|
|
2780
2942
|
}
|
|
2943
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtRepeat, decorators: [{
|
|
2944
|
+
type: Directive,
|
|
2945
|
+
args: [{ selector: '[ngFor][ngForRepeat]', standalone: true }]
|
|
2946
|
+
}], propDecorators: { ngForRepeat: [{
|
|
2947
|
+
type: Input
|
|
2948
|
+
}] } });
|
|
2781
2949
|
|
|
2782
2950
|
function injectNgtRef(initial = null, injector) {
|
|
2783
|
-
injector = assertInjectionContext(injectNgtRef
|
|
2951
|
+
injector = assertInjectionContext(injectNgtRef);
|
|
2784
2952
|
const ref = is.ref(initial) ? initial : new ElementRef(initial);
|
|
2785
2953
|
const signalRef = signal(ref.nativeElement);
|
|
2786
2954
|
const readonlySignal = signalRef.asReadonly();
|
|
2787
2955
|
const cached = new Map();
|
|
2788
2956
|
return runInInjectionContext(injector, () => {
|
|
2789
|
-
const cdr = inject(ChangeDetectorRef);
|
|
2790
2957
|
inject(DestroyRef).onDestroy(() => void cached.clear());
|
|
2791
2958
|
const children = (type = 'objects') => {
|
|
2792
2959
|
if (!cached.has(type)) {
|
|
@@ -2806,42 +2973,24 @@ function injectNgtRef(initial = null, injector) {
|
|
|
2806
2973
|
}
|
|
2807
2974
|
return cached.get(type);
|
|
2808
2975
|
};
|
|
2809
|
-
Object.
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
signalRef
|
|
2814
|
-
}
|
|
2815
|
-
catch {
|
|
2816
|
-
requestAnimationFrame(() => {
|
|
2976
|
+
Object.defineProperties(ref, {
|
|
2977
|
+
nativeElement: {
|
|
2978
|
+
set: (newElement) => {
|
|
2979
|
+
untracked(() => {
|
|
2980
|
+
if (newElement !== signalRef()) {
|
|
2817
2981
|
signalRef.set(newElement);
|
|
2818
|
-
}
|
|
2819
|
-
}
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
}
|
|
2982
|
+
}
|
|
2983
|
+
});
|
|
2984
|
+
},
|
|
2985
|
+
get: readonlySignal,
|
|
2823
2986
|
},
|
|
2824
|
-
get: () => readonlySignal
|
|
2987
|
+
untracked: { get: () => untracked(readonlySignal) },
|
|
2988
|
+
children: { get: () => children },
|
|
2825
2989
|
});
|
|
2826
|
-
|
|
2827
|
-
return Object.assign(ref, { children });
|
|
2990
|
+
return ref;
|
|
2828
2991
|
});
|
|
2829
2992
|
}
|
|
2830
2993
|
|
|
2831
|
-
class NgtRepeat extends NgForOf {
|
|
2832
|
-
set ngForRepeat(count) {
|
|
2833
|
-
this.ngForOf = Number.isInteger(count) ? Array.from({ length: count }, (_, i) => i) : [];
|
|
2834
|
-
}
|
|
2835
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: NgtRepeat, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2836
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.3", type: NgtRepeat, isStandalone: true, selector: "[ngFor][ngForRepeat]", inputs: { ngForRepeat: "ngForRepeat" }, usesInheritance: true, ngImport: i0 }); }
|
|
2837
|
-
}
|
|
2838
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: NgtRepeat, decorators: [{
|
|
2839
|
-
type: Directive,
|
|
2840
|
-
args: [{ selector: '[ngFor][ngForRepeat]', standalone: true }]
|
|
2841
|
-
}], propDecorators: { ngForRepeat: [{
|
|
2842
|
-
type: Input
|
|
2843
|
-
}] } });
|
|
2844
|
-
|
|
2845
2994
|
const privateKeys = [
|
|
2846
2995
|
'get',
|
|
2847
2996
|
'set',
|
|
@@ -2856,38 +3005,38 @@ const privateKeys = [
|
|
|
2856
3005
|
'viewport',
|
|
2857
3006
|
];
|
|
2858
3007
|
class NgtPortalBeforeRender {
|
|
2859
|
-
#portalStore;
|
|
2860
3008
|
constructor() {
|
|
2861
|
-
this
|
|
3009
|
+
this.portalStore = injectNgtStore();
|
|
3010
|
+
this.injector = inject(Injector);
|
|
2862
3011
|
this.renderPriority = 1;
|
|
2863
3012
|
this.beforeRender = new EventEmitter();
|
|
2864
|
-
let oldClear;
|
|
2865
|
-
requestAnimationFrameInInjectionContext(() => {
|
|
2866
|
-
injectBeforeRender(({ delta, frame }) => {
|
|
2867
|
-
this.beforeRender.emit({ ...this.#portalStore.get(), delta, frame });
|
|
2868
|
-
const { gl, scene, camera } = this.#portalStore.get();
|
|
2869
|
-
oldClear = gl.autoClear;
|
|
2870
|
-
if (this.renderPriority === 1) {
|
|
2871
|
-
// clear scene and render with default
|
|
2872
|
-
gl.autoClear = true;
|
|
2873
|
-
gl.render(this.parentScene, this.parentCamera);
|
|
2874
|
-
}
|
|
2875
|
-
// disable cleaning
|
|
2876
|
-
gl.autoClear = false;
|
|
2877
|
-
gl.clearDepth();
|
|
2878
|
-
gl.render(scene, camera);
|
|
2879
|
-
// restore
|
|
2880
|
-
gl.autoClear = oldClear;
|
|
2881
|
-
}, { priority: this.renderPriority });
|
|
2882
|
-
});
|
|
2883
3013
|
}
|
|
2884
|
-
|
|
2885
|
-
|
|
3014
|
+
ngOnInit() {
|
|
3015
|
+
let oldClear;
|
|
3016
|
+
injectBeforeRender(({ delta, frame }) => {
|
|
3017
|
+
this.beforeRender.emit({ ...this.portalStore.get(), delta, frame });
|
|
3018
|
+
const { gl, scene, camera } = this.portalStore.get();
|
|
3019
|
+
oldClear = gl.autoClear;
|
|
3020
|
+
if (this.renderPriority === 1) {
|
|
3021
|
+
// clear scene and render with default
|
|
3022
|
+
gl.autoClear = true;
|
|
3023
|
+
gl.render(this.parentScene, this.parentCamera);
|
|
3024
|
+
}
|
|
3025
|
+
// disable cleaning
|
|
3026
|
+
gl.autoClear = false;
|
|
3027
|
+
gl.clearDepth();
|
|
3028
|
+
gl.render(scene, camera);
|
|
3029
|
+
// restore
|
|
3030
|
+
gl.autoClear = oldClear;
|
|
3031
|
+
}, { priority: this.renderPriority, injector: this.injector });
|
|
3032
|
+
}
|
|
3033
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtPortalBeforeRender, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3034
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.1.7", type: NgtPortalBeforeRender, isStandalone: true, selector: "[ngtPortalBeforeRender]", inputs: { renderPriority: "renderPriority", parentScene: "parentScene", parentCamera: "parentCamera" }, outputs: { beforeRender: "beforeRender" }, ngImport: i0 }); }
|
|
2886
3035
|
}
|
|
2887
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
3036
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtPortalBeforeRender, decorators: [{
|
|
2888
3037
|
type: Directive,
|
|
2889
3038
|
args: [{ selector: '[ngtPortalBeforeRender]', standalone: true }]
|
|
2890
|
-
}],
|
|
3039
|
+
}], propDecorators: { renderPriority: [{
|
|
2891
3040
|
type: Input
|
|
2892
3041
|
}], parentScene: [{
|
|
2893
3042
|
type: Input,
|
|
@@ -2906,96 +3055,90 @@ class NgtPortalContent {
|
|
|
2906
3055
|
delete commentNode[SPECIAL_INTERNAL_ADD_COMMENT];
|
|
2907
3056
|
}
|
|
2908
3057
|
}
|
|
2909
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
2910
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.
|
|
3058
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtPortalContent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ViewContainerRef, skipSelf: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3059
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.1.7", type: NgtPortalContent, isStandalone: true, selector: "ng-template[ngtPortalContent]", ngImport: i0 }); }
|
|
2911
3060
|
}
|
|
2912
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
3061
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtPortalContent, decorators: [{
|
|
2913
3062
|
type: Directive,
|
|
2914
3063
|
args: [{ selector: 'ng-template[ngtPortalContent]', standalone: true }]
|
|
2915
3064
|
}], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ViewContainerRef, decorators: [{
|
|
2916
3065
|
type: SkipSelf
|
|
2917
3066
|
}] }]; } });
|
|
2918
|
-
class NgtPortal
|
|
3067
|
+
class NgtPortal {
|
|
2919
3068
|
set container(container) {
|
|
2920
|
-
this.set({ container });
|
|
3069
|
+
this.inputs.set({ container });
|
|
2921
3070
|
}
|
|
2922
3071
|
set portalState(state) {
|
|
2923
|
-
this.set({ state });
|
|
2924
|
-
}
|
|
2925
|
-
#parentStore;
|
|
2926
|
-
#portalStore;
|
|
2927
|
-
#injector;
|
|
2928
|
-
#zone;
|
|
2929
|
-
#raycaster;
|
|
2930
|
-
#pointer;
|
|
2931
|
-
#portalContentView;
|
|
3072
|
+
this.inputs.set({ state });
|
|
3073
|
+
}
|
|
2932
3074
|
constructor() {
|
|
2933
|
-
|
|
3075
|
+
this.inputs = signalStore({ container: injectNgtRef(prepare(new THREE.Scene())) });
|
|
2934
3076
|
this.autoRender = true;
|
|
2935
3077
|
this.autoRenderPriority = 1;
|
|
2936
3078
|
this.beforeRender = new EventEmitter();
|
|
2937
|
-
this
|
|
2938
|
-
this.parentScene = this
|
|
2939
|
-
this.parentCamera = this
|
|
2940
|
-
this
|
|
2941
|
-
this
|
|
2942
|
-
this
|
|
2943
|
-
this
|
|
2944
|
-
this
|
|
3079
|
+
this.parentStore = injectNgtStore({ skipSelf: true });
|
|
3080
|
+
this.parentScene = this.parentStore.get('scene');
|
|
3081
|
+
this.parentCamera = this.parentStore.get('camera');
|
|
3082
|
+
this.portalStore = injectNgtStore({ self: true });
|
|
3083
|
+
this.injector = inject(Injector);
|
|
3084
|
+
this.zone = inject(NgZone);
|
|
3085
|
+
this.raycaster = new THREE.Raycaster();
|
|
3086
|
+
this.pointer = new THREE.Vector2();
|
|
2945
3087
|
this.portalContentRendered = false;
|
|
2946
3088
|
inject(DestroyRef).onDestroy(() => {
|
|
2947
|
-
if (this
|
|
2948
|
-
this
|
|
3089
|
+
if (this.portalContentView && !this.portalContentView.destroyed) {
|
|
3090
|
+
this.portalContentView.destroy();
|
|
2949
3091
|
}
|
|
2950
3092
|
});
|
|
2951
3093
|
}
|
|
2952
3094
|
ngOnInit() {
|
|
2953
|
-
const previousState = this
|
|
2954
|
-
const inputsState = this.get();
|
|
3095
|
+
const previousState = this.parentStore.get();
|
|
3096
|
+
const inputsState = this.inputs.get();
|
|
2955
3097
|
if (!inputsState.state && this.autoRender) {
|
|
2956
3098
|
inputsState.state = { events: { priority: this.autoRenderPriority + 1 } };
|
|
2957
3099
|
}
|
|
2958
3100
|
const { events, size, ...restInputsState } = inputsState.state || {};
|
|
2959
3101
|
const containerState = inputsState.container;
|
|
2960
|
-
|
|
3102
|
+
let container = is.ref(containerState) ? containerState.nativeElement : containerState;
|
|
3103
|
+
if (!is.instance(container)) {
|
|
3104
|
+
container = prepare(container);
|
|
3105
|
+
}
|
|
2961
3106
|
const localState = getLocalState(container);
|
|
2962
3107
|
if (!localState.store) {
|
|
2963
|
-
localState.store = this
|
|
3108
|
+
localState.store = this.portalStore;
|
|
2964
3109
|
}
|
|
2965
|
-
this
|
|
3110
|
+
this.portalStore.set({
|
|
2966
3111
|
...previousState,
|
|
2967
3112
|
scene: container,
|
|
2968
|
-
raycaster: this
|
|
2969
|
-
pointer: this
|
|
2970
|
-
|
|
3113
|
+
raycaster: this.raycaster,
|
|
3114
|
+
pointer: this.pointer,
|
|
3115
|
+
previousRoot: this.parentStore,
|
|
2971
3116
|
events: { ...previousState.events, ...(events || {}) },
|
|
2972
3117
|
size: { ...previousState.size, ...(size || {}) },
|
|
2973
3118
|
...restInputsState,
|
|
2974
|
-
|
|
2975
|
-
set: this.#portalStore.set.bind(this.#portalStore),
|
|
2976
|
-
setEvents: (events) => this.#portalStore.set((state) => ({ ...state, events: { ...state.events, ...events } })),
|
|
3119
|
+
setEvents: (events) => this.portalStore.set((state) => ({ ...state, events: { ...state.events, ...events } })),
|
|
2977
3120
|
});
|
|
2978
|
-
const parentState = this
|
|
3121
|
+
const parentState = this.parentStore.select();
|
|
2979
3122
|
effect(() => {
|
|
2980
3123
|
const previous = parentState();
|
|
2981
|
-
this
|
|
2982
|
-
this
|
|
3124
|
+
this.zone.runOutsideAngular(() => {
|
|
3125
|
+
this.portalStore.set((state) => this.inject(previous, state));
|
|
2983
3126
|
});
|
|
2984
|
-
}, { injector: this
|
|
3127
|
+
}, { injector: this.injector });
|
|
2985
3128
|
requestAnimationFrame(() => {
|
|
2986
|
-
this
|
|
3129
|
+
this.portalStore.set((injectState) => this.inject(this.parentStore.get(), injectState));
|
|
2987
3130
|
});
|
|
2988
|
-
this
|
|
2989
|
-
safeDetectChanges(this
|
|
3131
|
+
this.portalContentView = this.portalContentAnchor.createEmbeddedView(this.portalContentTemplate);
|
|
3132
|
+
safeDetectChanges(this.portalContentView);
|
|
2990
3133
|
this.portalContentRendered = true;
|
|
2991
3134
|
}
|
|
2992
3135
|
onBeforeRender(portal) {
|
|
2993
3136
|
this.beforeRender.emit({
|
|
2994
|
-
root: { ...this
|
|
3137
|
+
root: { ...this.parentStore.get(), delta: portal.delta, frame: portal.frame },
|
|
2995
3138
|
portal,
|
|
2996
3139
|
});
|
|
2997
3140
|
}
|
|
2998
|
-
|
|
3141
|
+
inject(rootState, injectState) {
|
|
2999
3142
|
const intersect = { ...rootState };
|
|
3000
3143
|
Object.keys(intersect).forEach((key) => {
|
|
3001
3144
|
if (privateKeys.includes(key) ||
|
|
@@ -3003,7 +3146,7 @@ class NgtPortal extends NgtSignalStore {
|
|
|
3003
3146
|
delete intersect[key];
|
|
3004
3147
|
}
|
|
3005
3148
|
});
|
|
3006
|
-
const inputs = this.get();
|
|
3149
|
+
const inputs = this.inputs.get();
|
|
3007
3150
|
const { size, events, ...restInputsState } = inputs.state || {};
|
|
3008
3151
|
let viewport = undefined;
|
|
3009
3152
|
if (injectState && size) {
|
|
@@ -3015,53 +3158,54 @@ class NgtPortal extends NgtSignalStore {
|
|
|
3015
3158
|
return {
|
|
3016
3159
|
...intersect,
|
|
3017
3160
|
scene: is.ref(inputs.container) ? inputs.container.nativeElement : inputs.container,
|
|
3018
|
-
raycaster: this
|
|
3019
|
-
pointer: this
|
|
3020
|
-
|
|
3161
|
+
raycaster: this.raycaster,
|
|
3162
|
+
pointer: this.pointer,
|
|
3163
|
+
previousRoot: this.parentStore,
|
|
3021
3164
|
events: { ...rootState.events, ...(injectState?.events || {}), ...events },
|
|
3022
3165
|
size: { ...rootState.size, ...size },
|
|
3023
3166
|
viewport: { ...rootState.viewport, ...(viewport || {}) },
|
|
3024
3167
|
...restInputsState,
|
|
3025
3168
|
};
|
|
3026
3169
|
}
|
|
3027
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
3028
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3170
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtPortal, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3171
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.7", type: NgtPortal, isStandalone: true, selector: "ngt-portal", inputs: { container: "container", portalState: ["state", "portalState"], autoRender: "autoRender", autoRenderPriority: "autoRenderPriority" }, outputs: { beforeRender: "beforeRender" }, providers: [{ provide: NGT_STORE, useFactory: () => signalStore({}) }], 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 }], ngImport: i0, template: `
|
|
3172
|
+
<ng-container #portalContentAnchor>
|
|
3173
|
+
<ng-container
|
|
3174
|
+
*ngIf="autoRender && portalContentRendered"
|
|
3175
|
+
ngtPortalBeforeRender
|
|
3176
|
+
[renderPriority]="autoRenderPriority"
|
|
3177
|
+
[parentScene]="parentScene"
|
|
3178
|
+
[parentCamera]="parentCamera"
|
|
3179
|
+
(beforeRender)="onBeforeRender($event)"
|
|
3180
|
+
/>
|
|
3181
|
+
</ng-container>
|
|
3182
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgtPortalBeforeRender, selector: "[ngtPortalBeforeRender]", inputs: ["renderPriority", "parentScene", "parentCamera"], outputs: ["beforeRender"] }] }); }
|
|
3040
3183
|
}
|
|
3041
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
3184
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtPortal, decorators: [{
|
|
3042
3185
|
type: Component,
|
|
3043
3186
|
args: [{
|
|
3044
3187
|
selector: 'ngt-portal',
|
|
3045
3188
|
standalone: true,
|
|
3046
3189
|
template: `
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3190
|
+
<ng-container #portalContentAnchor>
|
|
3191
|
+
<ng-container
|
|
3192
|
+
*ngIf="autoRender && portalContentRendered"
|
|
3193
|
+
ngtPortalBeforeRender
|
|
3194
|
+
[renderPriority]="autoRenderPriority"
|
|
3195
|
+
[parentScene]="parentScene"
|
|
3196
|
+
[parentCamera]="parentCamera"
|
|
3197
|
+
(beforeRender)="onBeforeRender($event)"
|
|
3198
|
+
/>
|
|
3199
|
+
</ng-container>
|
|
3200
|
+
`,
|
|
3058
3201
|
imports: [NgIf, NgtPortalBeforeRender],
|
|
3059
|
-
providers: [
|
|
3202
|
+
providers: [{ provide: NGT_STORE, useFactory: () => signalStore({}) }],
|
|
3060
3203
|
}]
|
|
3061
3204
|
}], ctorParameters: function () { return []; }, propDecorators: { container: [{
|
|
3062
3205
|
type: Input
|
|
3063
3206
|
}], portalState: [{
|
|
3064
|
-
type: Input
|
|
3207
|
+
type: Input,
|
|
3208
|
+
args: ['state']
|
|
3065
3209
|
}], autoRender: [{
|
|
3066
3210
|
type: Input
|
|
3067
3211
|
}], autoRenderPriority: [{
|
|
@@ -3085,10 +3229,10 @@ class NgtRoutedScene {
|
|
|
3085
3229
|
.pipe(filter((event) => event instanceof ActivationEnd), takeUntilDestroyed())
|
|
3086
3230
|
.subscribe(() => safeDetectChanges(cdr));
|
|
3087
3231
|
}
|
|
3088
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
3089
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.
|
|
3232
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtRoutedScene, deps: [{ token: i1.Router }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3233
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.7", 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"] }] }); }
|
|
3090
3234
|
}
|
|
3091
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
3235
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: NgtRoutedScene, decorators: [{
|
|
3092
3236
|
type: Component,
|
|
3093
3237
|
args: [{
|
|
3094
3238
|
standalone: true,
|
|
@@ -3102,5 +3246,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImpor
|
|
|
3102
3246
|
* Generated bundle index. Do not edit.
|
|
3103
3247
|
*/
|
|
3104
3248
|
|
|
3105
|
-
export {
|
|
3249
|
+
export { HTML, NGT_STORE, NgtArgs, NgtCanvas, NgtKey, NgtParent, NgtPortal, NgtPortalContent, NgtRepeat, NgtRoutedScene, addAfterEffect, addEffect, addTail, applyProps, assertInjectionContext, checkNeedsUpdate, checkUpdate, createAttachFunction, createInjectionToken, diffProps, extend, getLocalState, injectBeforeRender, injectNgtLoader, injectNgtRef, injectNgtStore, invalidateInstance, is, makeDefaultCamera, makeDefaultRenderer, makeDpr, makeId, makeObjectGraph, prepare, provideNgtRenderer, provideNgtStore, safeDetectChanges, signalStore, updateCamera };
|
|
3106
3250
|
//# sourceMappingURL=angular-three.mjs.map
|