angular-three 2.0.0-beta.2 → 2.0.0-beta.21
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 +11 -10
- package/esm2022/lib/before-render.mjs +13 -0
- package/esm2022/lib/canvas.mjs +130 -161
- package/esm2022/lib/directives/args.mjs +13 -11
- package/esm2022/lib/directives/common.mjs +29 -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 +30 -37
- package/esm2022/lib/loop.mjs +6 -3
- package/esm2022/lib/portal.mjs +91 -102
- 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 +419 -0
- package/esm2022/lib/renderer/store.mjs +144 -108
- package/esm2022/lib/renderer/utils.mjs +63 -48
- package/esm2022/lib/roots.mjs +249 -0
- package/esm2022/lib/routed-scene.mjs +11 -8
- package/esm2022/lib/store.mjs +207 -0
- package/esm2022/lib/three-types.mjs +2 -2
- package/esm2022/lib/types.mjs +1 -1
- package/esm2022/lib/utils/apply-props.mjs +23 -11
- 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 +1770 -1589
- package/fesm2022/angular-three.mjs.map +1 -1
- package/index.d.ts +10 -9
- 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 +20 -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 +19 -15
- package/lib/renderer/utils.d.ts +28 -18
- 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 +6 -6
- package/lib/types.d.ts +1 -309
- package/lib/utils/apply-props.d.ts +4 -2
- package/lib/utils/attach.d.ts +5 -3
- package/lib/utils/create-injection-token.d.ts +27 -0
- package/lib/utils/is.d.ts +4 -3
- 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 -1
- package/package.json +5 -4
- package/plugin/generators.json +47 -17
- package/plugin/package.json +2 -5
- package/plugin/src/generators/init/compat.d.ts +3 -1
- package/plugin/src/generators/init/compat.js +2 -2
- package/plugin/src/generators/init/compat.js.map +1 -1
- package/plugin/src/generators/init/files/experience/experience.component.html.__tmpl__ +4 -0
- package/plugin/src/generators/init/files/experience/experience.component.ts.__tmpl__ +17 -0
- package/plugin/src/generators/init/generator.d.ts +6 -0
- package/plugin/src/generators/init/generator.js +144 -0
- package/plugin/src/generators/init/generator.js.map +1 -0
- package/plugin/src/generators/init/schema.json +15 -4
- package/plugin/src/generators/init-cannon/compat.d.ts +2 -0
- package/plugin/src/generators/init-cannon/compat.js +6 -0
- package/plugin/src/generators/init-cannon/compat.js.map +1 -0
- package/plugin/src/generators/init-cannon/generator.d.ts +2 -0
- package/plugin/src/generators/init-cannon/generator.js +22 -0
- package/plugin/src/generators/init-cannon/generator.js.map +1 -0
- package/plugin/src/generators/init-cannon/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 +26 -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/utils.d.ts +2 -0
- package/plugin/src/generators/utils.js +34 -0
- package/plugin/src/generators/utils.js.map +1 -0
- package/plugin/src/generators/versions.d.ts +12 -0
- package/plugin/src/generators/versions.js +16 -0
- package/plugin/src/generators/versions.js.map +1 -0
- package/plugin/src/index.d.ts +3 -1
- package/plugin/src/index.js +7 -3
- package/plugin/src/index.js.map +1 -1
- package/web-types.json +1 -1
- package/esm2022/lib/di/before-render.mjs +0 -13
- package/esm2022/lib/di/catalogue.mjs +0 -7
- package/esm2022/lib/di/ref.mjs +0 -49
- 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 -365
- package/esm2022/lib/stores/signal.store.mjs +0 -81
- package/esm2022/lib/stores/store.mjs +0 -423
- package/esm2022/lib/utils/assert-in-injection-context.mjs +0 -14
- package/esm2022/lib/utils/instance.mjs +0 -63
- package/esm2022/lib/utils/signal.mjs +0 -24
- package/esm2022/lib/utils/timing.mjs +0 -21
- 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 -20
- package/lib/stores/store.d.ts +0 -13
- package/lib/utils/instance.d.ts +0 -4
- package/lib/utils/signal.d.ts +0 -2
- package/lib/utils/timing.d.ts +0 -4
- package/plugin/src/generators/init/init.d.ts +0 -5
- package/plugin/src/generators/init/init.js +0 -56
- package/plugin/src/generators/init/init.js.map +0 -1
- /package/lib/utils/{assert-in-injection-context.d.ts → assert-injection-context.d.ts} +0 -0
|
@@ -1,107 +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
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
22
|
};
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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;
|
|
30
36
|
};
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
Object.keys(partial).forEach((key) => {
|
|
71
|
-
const partialKey = key;
|
|
72
|
-
if (partial[partialKey] === undefined && previous[partialKey] != null) {
|
|
73
|
-
partial[partialKey] = previous[partialKey];
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
return partial;
|
|
77
|
-
};
|
|
78
|
-
this.#state.update((previous) => ({ ...previous, ...updater(previous) }));
|
|
79
|
-
// this.#state.update(previous => ({...previous, ...(typeof state === 'function' ? state(previous) : state)}))
|
|
80
|
-
}
|
|
81
|
-
patch(state) {
|
|
82
|
-
const updater = (previous) => {
|
|
83
|
-
Object.keys(state).forEach((key) => {
|
|
84
|
-
const partialKey = key;
|
|
85
|
-
if (state[partialKey] === undefined && previous[partialKey] != null) {
|
|
86
|
-
state[partialKey] = previous[partialKey];
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
return state;
|
|
90
|
-
};
|
|
91
|
-
this.#state.update((previous) => ({ ...updater(previous), ...previous }));
|
|
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 }));
|
|
92
76
|
}
|
|
93
|
-
|
|
94
|
-
|
|
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;
|
|
95
93
|
}
|
|
96
|
-
|
|
97
|
-
type: Injectable
|
|
98
|
-
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
|
99
|
-
type: Optional
|
|
100
|
-
}, {
|
|
101
|
-
type: Inject,
|
|
102
|
-
args: ['INITIAL_STATE']
|
|
103
|
-
}] }]; } });
|
|
104
|
-
function parseOptions(keysAndOptions) {
|
|
94
|
+
function parseStoreOptions(keysAndOptions) {
|
|
105
95
|
if (typeof keysAndOptions.at(-1) === 'object') {
|
|
106
96
|
return [keysAndOptions.slice(0, -1), keysAndOptions.at(-1)];
|
|
107
97
|
}
|
|
@@ -203,34 +193,37 @@ function invalidateInstance(instance) {
|
|
|
203
193
|
function prepare(object, localState) {
|
|
204
194
|
const instance = object;
|
|
205
195
|
if (localState?.primitive || !instance.__ngt__) {
|
|
206
|
-
const { objects =
|
|
196
|
+
const { objects = signal([]), nonObjects = signal([]), ...rest } = localState || {};
|
|
207
197
|
instance.__ngt__ = {
|
|
208
198
|
previousAttach: null,
|
|
209
199
|
store: null,
|
|
210
|
-
parent:
|
|
200
|
+
parent: signal(null),
|
|
211
201
|
memoized: {},
|
|
212
202
|
eventCount: 0,
|
|
213
203
|
handlers: {},
|
|
214
204
|
objects,
|
|
215
205
|
nonObjects,
|
|
216
|
-
nativeProps:
|
|
206
|
+
nativeProps: signalStore(),
|
|
217
207
|
add: (object, type) => {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
208
|
+
untracked(() => {
|
|
209
|
+
const current = instance.__ngt__[type]();
|
|
210
|
+
const foundIndex = current.indexOf((obj) => obj === object);
|
|
211
|
+
if (foundIndex > -1) {
|
|
212
|
+
// if we add an object with the same reference, then we switch it out
|
|
213
|
+
current.splice(foundIndex, 1, object);
|
|
214
|
+
instance.__ngt__[type].set(current);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
instance.__ngt__[type].update((prev) => [...prev, object]);
|
|
218
|
+
}
|
|
219
|
+
notifyAncestors(instance.__ngt__.parent());
|
|
220
|
+
});
|
|
230
221
|
},
|
|
231
222
|
remove: (object, type) => {
|
|
232
|
-
|
|
233
|
-
|
|
223
|
+
untracked(() => {
|
|
224
|
+
instance.__ngt__[type].update((prev) => prev.filter((o) => o !== object));
|
|
225
|
+
notifyAncestors(instance.__ngt__.parent());
|
|
226
|
+
});
|
|
234
227
|
},
|
|
235
228
|
...rest,
|
|
236
229
|
};
|
|
@@ -245,7 +238,142 @@ function notifyAncestors(instance) {
|
|
|
245
238
|
localState.objects.update((prev) => prev);
|
|
246
239
|
if (localState.nonObjects)
|
|
247
240
|
localState.nonObjects.update((prev) => prev);
|
|
248
|
-
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
|
+
}
|
|
249
377
|
}
|
|
250
378
|
|
|
251
379
|
const idCache = {};
|
|
@@ -297,89 +425,734 @@ function makeObjectGraph(object) {
|
|
|
297
425
|
return data;
|
|
298
426
|
}
|
|
299
427
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
+
};
|
|
324
647
|
});
|
|
325
|
-
if (store.get('previousStore')) {
|
|
326
|
-
removeInteractivity(store.get('previousStore'), object);
|
|
327
|
-
}
|
|
328
648
|
}
|
|
329
|
-
function
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const dy = event.offsetY - internal.initialClick[1];
|
|
335
|
-
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();
|
|
336
654
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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];
|
|
343
664
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
instanceState.raycaster.camera = undefined;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
if (!state.previousStore) {
|
|
358
|
-
// make sure root-level pointer and ray are setup
|
|
359
|
-
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 };
|
|
360
675
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
const objStore = objLocalState.store;
|
|
364
|
-
const objState = objStore?.get();
|
|
365
|
-
// skip event handling when noEvents is set, or when raycaster camera is null
|
|
366
|
-
if (!objState || !objState.events.enabled || objState.raycaster.camera === null)
|
|
367
|
-
return [];
|
|
368
|
-
// when the camera is undefined, we have to call the events layers to update function
|
|
369
|
-
if (objState.raycaster.camera === undefined) {
|
|
370
|
-
objState.events.compute?.(event, objStore, objState.previousStore);
|
|
371
|
-
// if the camera is still undefined, we have to skip this layer entirely
|
|
372
|
-
if (objState.raycaster.camera === undefined)
|
|
373
|
-
objState.raycaster.camera = null;
|
|
374
|
-
}
|
|
375
|
-
// intersect object by object
|
|
376
|
-
return objState.raycaster.camera ? objState.raycaster.intersectObject(obj, true) : [];
|
|
676
|
+
else {
|
|
677
|
+
provider = { provide: token, useFactory: factory, deps: (deps ?? []) };
|
|
377
678
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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
|
|
381
1154
|
.flatMap(handleRaycast)
|
|
382
|
-
//
|
|
1155
|
+
// Sort by event priority and distance
|
|
383
1156
|
.sort((a, b) => {
|
|
384
1157
|
const aState = getLocalState(a.object).store.get();
|
|
385
1158
|
const bState = getLocalState(b.object).store.get();
|
|
@@ -387,7 +1160,7 @@ function createEvents(store) {
|
|
|
387
1160
|
return a.distance - b.distance;
|
|
388
1161
|
return bState.events.priority - aState.events.priority || a.distance - b.distance;
|
|
389
1162
|
})
|
|
390
|
-
//
|
|
1163
|
+
// Filter out duplicates
|
|
391
1164
|
.filter((item) => {
|
|
392
1165
|
const id = makeId(item);
|
|
393
1166
|
if (duplicates.has(id))
|
|
@@ -395,10 +1168,11 @@ function createEvents(store) {
|
|
|
395
1168
|
duplicates.add(id);
|
|
396
1169
|
return true;
|
|
397
1170
|
});
|
|
398
|
-
//
|
|
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
|
|
399
1173
|
if (state.events.filter)
|
|
400
1174
|
hits = state.events.filter(hits, store);
|
|
401
|
-
//
|
|
1175
|
+
// Bubble up the events, find the event source (eventObject)
|
|
402
1176
|
for (const hit of hits) {
|
|
403
1177
|
let eventObject = hit.object;
|
|
404
1178
|
// bubble event up
|
|
@@ -409,20 +1183,19 @@ function createEvents(store) {
|
|
|
409
1183
|
eventObject = eventObject.parent;
|
|
410
1184
|
}
|
|
411
1185
|
}
|
|
412
|
-
//
|
|
1186
|
+
// If the interaction is captured, make all capturing targets part of the intersect.
|
|
413
1187
|
if ('pointerId' in event && state.internal.capturedMap.has(event.pointerId)) {
|
|
414
|
-
for (
|
|
415
|
-
if (!duplicates.has(makeId(
|
|
416
|
-
intersections.push(
|
|
417
|
-
}
|
|
1188
|
+
for (let captureData of state.internal.capturedMap.get(event.pointerId).values()) {
|
|
1189
|
+
if (!duplicates.has(makeId(captureData.intersection)))
|
|
1190
|
+
intersections.push(captureData.intersection);
|
|
418
1191
|
}
|
|
419
1192
|
}
|
|
420
1193
|
return intersections;
|
|
421
1194
|
}
|
|
422
|
-
/**
|
|
1195
|
+
/** Handles intersections by forwarding them to handlers */
|
|
423
1196
|
function handleIntersects(intersections, event, delta, callback) {
|
|
424
1197
|
const rootState = store.get();
|
|
425
|
-
//
|
|
1198
|
+
// If anything has been found, forward it to the event listeners
|
|
426
1199
|
if (intersections.length) {
|
|
427
1200
|
const localState = { stopped: false };
|
|
428
1201
|
for (const hit of intersections) {
|
|
@@ -433,14 +1206,17 @@ function createEvents(store) {
|
|
|
433
1206
|
const setPointerCapture = (id) => {
|
|
434
1207
|
const captureData = { intersection: hit, target: event.target };
|
|
435
1208
|
if (internal.capturedMap.has(id)) {
|
|
436
|
-
// 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.
|
|
437
1211
|
internal.capturedMap.get(id).set(hit.eventObject, captureData);
|
|
438
1212
|
}
|
|
439
1213
|
else {
|
|
440
|
-
// 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.
|
|
441
1217
|
internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
|
|
442
1218
|
}
|
|
443
|
-
//
|
|
1219
|
+
// Call the original event now
|
|
444
1220
|
event.target.setPointerCapture(id);
|
|
445
1221
|
};
|
|
446
1222
|
const releasePointerCapture = (id) => {
|
|
@@ -449,15 +1225,15 @@ function createEvents(store) {
|
|
|
449
1225
|
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
450
1226
|
}
|
|
451
1227
|
};
|
|
452
|
-
//
|
|
1228
|
+
// Add native event props
|
|
453
1229
|
const extractEventProps = {};
|
|
454
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.
|
|
455
|
-
for (
|
|
456
|
-
|
|
457
|
-
//
|
|
458
|
-
|
|
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')
|
|
459
1236
|
extractEventProps[prop] = property;
|
|
460
|
-
}
|
|
461
1237
|
}
|
|
462
1238
|
const raycastEvent = {
|
|
463
1239
|
...hit,
|
|
@@ -468,7 +1244,7 @@ function createEvents(store) {
|
|
|
468
1244
|
delta,
|
|
469
1245
|
unprojectedPoint,
|
|
470
1246
|
ray: raycaster.ray,
|
|
471
|
-
camera
|
|
1247
|
+
camera,
|
|
472
1248
|
// Hijack stopPropagation, which just sets a flag
|
|
473
1249
|
stopPropagation() {
|
|
474
1250
|
// https://github.com/pmndrs/react-three-fiber/issues/596
|
|
@@ -496,9 +1272,9 @@ function createEvents(store) {
|
|
|
496
1272
|
currentTarget: { hasPointerCapture, setPointerCapture, releasePointerCapture },
|
|
497
1273
|
nativeEvent: event,
|
|
498
1274
|
};
|
|
499
|
-
//
|
|
1275
|
+
// Call subscribers
|
|
500
1276
|
callback(raycastEvent);
|
|
501
|
-
//
|
|
1277
|
+
// Event bubbling may be interrupted by stopPropagation
|
|
502
1278
|
if (localState.stopped === true)
|
|
503
1279
|
break;
|
|
504
1280
|
}
|
|
@@ -506,9 +1282,9 @@ function createEvents(store) {
|
|
|
506
1282
|
return intersections;
|
|
507
1283
|
}
|
|
508
1284
|
function cancelPointer(intersections) {
|
|
509
|
-
const
|
|
1285
|
+
const internal = store.get('internal');
|
|
510
1286
|
for (const hoveredObj of internal.hovered.values()) {
|
|
511
|
-
// 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
|
|
512
1288
|
// we call onPointerOut and delete the object from the hovered-elements map
|
|
513
1289
|
if (!intersections.length ||
|
|
514
1290
|
!intersections.find((hit) => hit.object === hoveredObj.object &&
|
|
@@ -552,14 +1328,14 @@ function createEvents(store) {
|
|
|
552
1328
|
}
|
|
553
1329
|
// Any other pointer goes here ...
|
|
554
1330
|
return function handleEvent(event) {
|
|
555
|
-
const
|
|
1331
|
+
const pointerMissed$ = store['pointerMissed$'];
|
|
1332
|
+
const internal = store.get('internal');
|
|
556
1333
|
// prepareRay(event)
|
|
557
1334
|
internal.lastEvent.nativeElement = event;
|
|
558
1335
|
// Get fresh intersects
|
|
559
1336
|
const isPointerMove = name === 'pointermove';
|
|
560
1337
|
const isClickEvent = name === 'click' || name === 'contextmenu' || name === 'dblclick';
|
|
561
1338
|
const filter = isPointerMove ? filterPointerEvents : undefined;
|
|
562
|
-
// const hits = patchIntersects(intersect(filter), event)
|
|
563
1339
|
const hits = intersect(event, filter);
|
|
564
1340
|
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
565
1341
|
// Save initial coordinates on pointer-down
|
|
@@ -572,8 +1348,7 @@ function createEvents(store) {
|
|
|
572
1348
|
if (isClickEvent && !hits.length) {
|
|
573
1349
|
if (delta <= 2) {
|
|
574
1350
|
pointerMissed(event, internal.interaction);
|
|
575
|
-
|
|
576
|
-
onPointerMissed(event);
|
|
1351
|
+
pointerMissed$.next(event);
|
|
577
1352
|
}
|
|
578
1353
|
}
|
|
579
1354
|
// Take care of unhover
|
|
@@ -586,6 +1361,20 @@ function createEvents(store) {
|
|
|
586
1361
|
// Check presence of handlers
|
|
587
1362
|
if (!instance?.eventCount)
|
|
588
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
|
+
}*/
|
|
589
1378
|
if (isPointerMove) {
|
|
590
1379
|
// Move event ...
|
|
591
1380
|
if (handlers?.pointerover ||
|
|
@@ -680,6 +1469,11 @@ function createPointerEvents(store) {
|
|
|
680
1469
|
handlers[supportedEventName] = handlePointer(supportedEventName);
|
|
681
1470
|
return handlers;
|
|
682
1471
|
}, {}),
|
|
1472
|
+
update: () => {
|
|
1473
|
+
const { events, internal } = store.get();
|
|
1474
|
+
if (internal.lastEvent?.nativeElement && events.handlers)
|
|
1475
|
+
events.handlers.pointermove(internal.lastEvent.nativeElement);
|
|
1476
|
+
},
|
|
683
1477
|
connect: (target) => {
|
|
684
1478
|
const state = store.get();
|
|
685
1479
|
state.events.disconnect?.();
|
|
@@ -703,95 +1497,45 @@ function createPointerEvents(store) {
|
|
|
703
1497
|
};
|
|
704
1498
|
}
|
|
705
1499
|
|
|
706
|
-
function assertInjectionContext(fn, injector) {
|
|
707
|
-
try {
|
|
708
|
-
if (!injector) {
|
|
709
|
-
return inject(Injector);
|
|
710
|
-
}
|
|
711
|
-
return injector;
|
|
712
|
-
}
|
|
713
|
-
catch {
|
|
714
|
-
!injector && assertInInjectionContext(fn);
|
|
715
|
-
return null;
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
function safeDetectChanges(cdr) {
|
|
720
|
-
if (!cdr)
|
|
721
|
-
return;
|
|
722
|
-
try {
|
|
723
|
-
// dynamic created component with ViewContainerRef#createComponent does not have Context
|
|
724
|
-
// but it has _attachedToViewContainer
|
|
725
|
-
if (cdr['_attachedToViewContainer'] || !!cdr['context']) {
|
|
726
|
-
cdr.detectChanges();
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
catch (e) {
|
|
730
|
-
cdr.markForCheck();
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
function requestAnimationInInjectionContext(cb, injector) {
|
|
735
|
-
injector = assertInjectionContext(requestAnimationInInjectionContext, injector);
|
|
736
|
-
return requestAnimationFrame(() => {
|
|
737
|
-
return runInInjectionContext(injector, cb);
|
|
738
|
-
});
|
|
739
|
-
}
|
|
740
|
-
function queueMicrotaskInInjectionContext(cb, injector) {
|
|
741
|
-
injector = assertInjectionContext(requestAnimationInInjectionContext, injector);
|
|
742
|
-
return queueMicrotask(() => {
|
|
743
|
-
return runInInjectionContext(injector, cb);
|
|
744
|
-
});
|
|
745
|
-
}
|
|
746
|
-
function queueMacrotaskInInjectionContext(cb, injector) {
|
|
747
|
-
injector = assertInjectionContext(requestAnimationInInjectionContext, injector);
|
|
748
|
-
return setTimeout(() => {
|
|
749
|
-
return runInInjectionContext(injector, cb);
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
|
-
|
|
753
1500
|
const cached = new Map();
|
|
1501
|
+
function normalizeInputs(input) {
|
|
1502
|
+
if (Array.isArray(input))
|
|
1503
|
+
return input;
|
|
1504
|
+
if (typeof input === 'string')
|
|
1505
|
+
return [input];
|
|
1506
|
+
return Object.values(input);
|
|
1507
|
+
}
|
|
754
1508
|
function load(loaderConstructorFactory, inputs, { extensions, onProgress, } = {}) {
|
|
755
|
-
const computedUrls = computed(() => {
|
|
756
|
-
const input = inputs();
|
|
757
|
-
if (Array.isArray(input))
|
|
758
|
-
return input;
|
|
759
|
-
if (typeof input === 'string')
|
|
760
|
-
return [input];
|
|
761
|
-
return Object.values(input);
|
|
762
|
-
});
|
|
763
1509
|
return () => {
|
|
764
|
-
const urls =
|
|
765
|
-
const
|
|
766
|
-
const loader = new loaderConstructor();
|
|
1510
|
+
const urls = normalizeInputs(inputs());
|
|
1511
|
+
const loader = new (loaderConstructorFactory(urls))();
|
|
767
1512
|
if (extensions)
|
|
768
1513
|
extensions(loader);
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
}, onProgress, (error) => reject(new Error(`[NGT] Could not load ${url}: ${error}`)));
|
|
1514
|
+
// TODO: reevaluate this
|
|
1515
|
+
return urls.map((url) => {
|
|
1516
|
+
if (!cached.has(url)) {
|
|
1517
|
+
cached.set(url, new Promise((resolve, reject) => {
|
|
1518
|
+
loader.load(url, (data) => {
|
|
1519
|
+
if ('scene' in data)
|
|
1520
|
+
Object.assign(data, makeObjectGraph(data['scene']));
|
|
1521
|
+
resolve(data);
|
|
1522
|
+
}, onProgress, (error) => reject(new Error(`[NGT] Could not load ${url}: ${error}`)));
|
|
1523
|
+
}));
|
|
780
1524
|
}
|
|
781
|
-
|
|
1525
|
+
return cached.get(url);
|
|
1526
|
+
});
|
|
782
1527
|
};
|
|
783
1528
|
}
|
|
784
1529
|
function injectNgtLoader(loaderConstructorFactory, inputs, { extensions, onProgress, injector, } = {}) {
|
|
785
1530
|
injector = assertInjectionContext(injectNgtLoader, injector);
|
|
1531
|
+
const response = signal(null);
|
|
786
1532
|
return runInInjectionContext(injector, () => {
|
|
787
1533
|
const cdr = inject(ChangeDetectorRef);
|
|
788
|
-
const response = signal(null);
|
|
789
1534
|
const effector = load(loaderConstructorFactory, inputs, { extensions, onProgress });
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
.then((results) => {
|
|
1535
|
+
effect(() => {
|
|
1536
|
+
const originalUrls = inputs();
|
|
1537
|
+
Promise.all(effector()).then((results) => {
|
|
1538
|
+
response.update(() => {
|
|
795
1539
|
if (Array.isArray(originalUrls))
|
|
796
1540
|
return results;
|
|
797
1541
|
if (typeof originalUrls === 'string')
|
|
@@ -801,11 +1545,8 @@ function injectNgtLoader(loaderConstructorFactory, inputs, { extensions, onProgr
|
|
|
801
1545
|
result[key] = results[keys.indexOf(key)];
|
|
802
1546
|
return result;
|
|
803
1547
|
}, {});
|
|
804
|
-
})
|
|
805
|
-
.then((value) => {
|
|
806
|
-
response.set(value);
|
|
807
|
-
safeDetectChanges(cdr);
|
|
808
1548
|
});
|
|
1549
|
+
safeDetectChanges(cdr);
|
|
809
1550
|
});
|
|
810
1551
|
});
|
|
811
1552
|
return response.asReadonly();
|
|
@@ -813,674 +1554,138 @@ function injectNgtLoader(loaderConstructorFactory, inputs, { extensions, onProgr
|
|
|
813
1554
|
}
|
|
814
1555
|
injectNgtLoader['preload'] = (loaderConstructorFactory, inputs, extensions) => {
|
|
815
1556
|
Promise.all(load(loaderConstructorFactory, inputs, { extensions })());
|
|
816
|
-
};
|
|
817
|
-
injectNgtLoader['destroy'] = () => {
|
|
818
|
-
cached.clear();
|
|
819
|
-
};
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
const
|
|
828
|
-
const
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
function render(timestamp, store, frame) {
|
|
862
|
-
const state = store.get();
|
|
863
|
-
// Run local effects
|
|
864
|
-
let delta = state.clock.getDelta();
|
|
865
|
-
// In frameloop='never' mode, clock times are updated using the provided timestamp
|
|
866
|
-
if (state.frameloop === 'never' && typeof timestamp === 'number') {
|
|
867
|
-
delta = timestamp - state.clock.elapsedTime;
|
|
868
|
-
state.clock.oldTime = state.clock.elapsedTime;
|
|
869
|
-
state.clock.elapsedTime = timestamp;
|
|
870
|
-
}
|
|
871
|
-
// Call subscribers (useFrame)
|
|
872
|
-
const subscribers = state.internal.subscribers;
|
|
873
|
-
for (let i = 0; i < subscribers.length; i++) {
|
|
874
|
-
const subscription = subscribers[i];
|
|
875
|
-
subscription.callback({ ...subscription.store.get(), delta, frame });
|
|
876
|
-
}
|
|
877
|
-
// Render content
|
|
878
|
-
if (!state.internal.priority && state.gl.render)
|
|
879
|
-
state.gl.render(state.scene, state.camera);
|
|
880
|
-
// Decrease frame count
|
|
881
|
-
state.internal.frames = Math.max(0, state.internal.frames - 1);
|
|
882
|
-
return state.frameloop === 'always' ? 1 : state.internal.frames;
|
|
883
|
-
}
|
|
884
|
-
function createLoop(roots) {
|
|
885
|
-
let running = false;
|
|
886
|
-
let repeat;
|
|
887
|
-
let frame;
|
|
888
|
-
function loop(timestamp) {
|
|
889
|
-
frame = requestAnimationFrame(loop);
|
|
890
|
-
running = true;
|
|
891
|
-
repeat = 0;
|
|
892
|
-
// Run effects
|
|
893
|
-
flushGlobalEffects('before', timestamp);
|
|
894
|
-
// Render all roots
|
|
895
|
-
for (const root of roots.values()) {
|
|
896
|
-
const state = root.get();
|
|
897
|
-
// If the frameloop is invalidated, do not run another frame
|
|
898
|
-
if (state.internal.active &&
|
|
899
|
-
(state.frameloop === 'always' || state.internal.frames > 0) &&
|
|
900
|
-
!state.gl.xr?.isPresenting) {
|
|
901
|
-
repeat += render(timestamp, root);
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
// Run after-effects
|
|
905
|
-
flushGlobalEffects('after', timestamp);
|
|
906
|
-
// Stop the loop if nothing invalidates it
|
|
907
|
-
if (repeat === 0) {
|
|
908
|
-
// Tail call effects, they are called when rendering stops
|
|
909
|
-
flushGlobalEffects('tail', timestamp);
|
|
910
|
-
// Flag end of operation
|
|
911
|
-
running = false;
|
|
912
|
-
return cancelAnimationFrame(frame);
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
function invalidate(store, frames = 1) {
|
|
916
|
-
const state = store?.get();
|
|
917
|
-
if (!state)
|
|
918
|
-
return roots.forEach((root) => invalidate(root, frames));
|
|
919
|
-
if (state.gl.xr?.isPresenting || !state.internal.active || state.frameloop === 'never')
|
|
920
|
-
return;
|
|
921
|
-
// Increase frames, do not go higher than 60
|
|
922
|
-
state.internal.frames = Math.min(60, state.internal.frames + frames);
|
|
923
|
-
// If the render-loop isn't active, start it
|
|
924
|
-
if (!running) {
|
|
925
|
-
running = true;
|
|
926
|
-
requestAnimationFrame(loop);
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
function advance(timestamp, runGlobalEffects = true, store, frame) {
|
|
930
|
-
const state = store?.get();
|
|
931
|
-
if (runGlobalEffects)
|
|
932
|
-
flushGlobalEffects('before', timestamp);
|
|
933
|
-
if (!state)
|
|
934
|
-
for (const root of roots.values())
|
|
935
|
-
render(timestamp, root);
|
|
936
|
-
else
|
|
937
|
-
render(timestamp, store, frame);
|
|
938
|
-
if (runGlobalEffects)
|
|
939
|
-
flushGlobalEffects('after', timestamp);
|
|
940
|
-
}
|
|
941
|
-
return {
|
|
942
|
-
loop,
|
|
943
|
-
/**
|
|
944
|
-
* Invalidates the view, requesting a frame to be rendered. Will globally invalidate unless passed a root's state.
|
|
945
|
-
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#invalidate
|
|
946
|
-
*/
|
|
947
|
-
invalidate,
|
|
948
|
-
/**
|
|
949
|
-
* Advances the frameloop and runs render effects, useful for when manually rendering via `frameloop="never"`.
|
|
950
|
-
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#advance
|
|
951
|
-
*/
|
|
952
|
-
advance,
|
|
953
|
-
};
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
function diffProps(instance, props) {
|
|
957
|
-
const propsEntries = Object.entries(props);
|
|
958
|
-
const changes = [];
|
|
959
|
-
for (const [propKey, propValue] of propsEntries) {
|
|
960
|
-
if (is.equ(propValue, instance[propKey]))
|
|
961
|
-
continue;
|
|
962
|
-
changes.push([propKey, propValue]);
|
|
963
|
-
}
|
|
964
|
-
return changes;
|
|
965
|
-
}
|
|
966
|
-
function applyProps(instance, props) {
|
|
967
|
-
// if props is empty
|
|
968
|
-
if (!Object.keys(props).length)
|
|
969
|
-
return instance;
|
|
970
|
-
// filter equals, events , and reserved props
|
|
971
|
-
const localState = getLocalState(instance);
|
|
972
|
-
const rootState = localState.store?.get();
|
|
973
|
-
const changes = diffProps(instance, props);
|
|
974
|
-
for (let i = 0; i < changes.length; i++) {
|
|
975
|
-
let key = changes[i][0];
|
|
976
|
-
const currentInstance = instance;
|
|
977
|
-
const targetProp = currentInstance[key];
|
|
978
|
-
let value = changes[i][1];
|
|
979
|
-
if (is.colorSpaceExist(currentInstance)) {
|
|
980
|
-
const sRGBEncoding = 3001;
|
|
981
|
-
const SRGBColorSpace = 'srgb';
|
|
982
|
-
const LinearSRGBColorSpace = 'srgb-linear';
|
|
983
|
-
if (key === 'encoding') {
|
|
984
|
-
key = 'colorSpace';
|
|
985
|
-
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
986
|
-
}
|
|
987
|
-
else if (key === 'outputEncoding') {
|
|
988
|
-
key = 'outputColorSpace';
|
|
989
|
-
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
// special treatmen for objects with support for set/copy, and layers
|
|
993
|
-
if (targetProp && targetProp['set'] && (targetProp['copy'] || targetProp instanceof THREE.Layers)) {
|
|
994
|
-
const isColor = targetProp instanceof THREE.Color;
|
|
995
|
-
// if value is an array
|
|
996
|
-
if (Array.isArray(value)) {
|
|
997
|
-
if (targetProp['fromArray'])
|
|
998
|
-
targetProp['fromArray'](value);
|
|
999
|
-
else
|
|
1000
|
-
targetProp['set'](...value);
|
|
1001
|
-
}
|
|
1002
|
-
// test again target.copy
|
|
1003
|
-
else if (targetProp['copy'] &&
|
|
1004
|
-
value &&
|
|
1005
|
-
value.constructor &&
|
|
1006
|
-
targetProp.constructor.name === value.constructor.name) {
|
|
1007
|
-
targetProp['copy'](value);
|
|
1008
|
-
if (!THREE.ColorManagement && !rootState.linear && isColor)
|
|
1009
|
-
targetProp['convertSRGBToLinear']();
|
|
1010
|
-
}
|
|
1011
|
-
// if nothing else fits, just set the single value, ignore undefined
|
|
1012
|
-
else if (value !== undefined) {
|
|
1013
|
-
const isColor = targetProp instanceof THREE.Color;
|
|
1014
|
-
// allow setting array scalars
|
|
1015
|
-
if (!isColor && targetProp['setScalar'])
|
|
1016
|
-
targetProp['setScalar'](value);
|
|
1017
|
-
// layers have no copy function, copy the mask
|
|
1018
|
-
else if (targetProp instanceof THREE.Layers && value instanceof THREE.Layers)
|
|
1019
|
-
targetProp.mask = value.mask;
|
|
1020
|
-
// otherwise just set ...
|
|
1021
|
-
else
|
|
1022
|
-
targetProp['set'](value);
|
|
1023
|
-
// auto-convert srgb
|
|
1024
|
-
if (!THREE.ColorManagement && !rootState?.linear && isColor)
|
|
1025
|
-
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];
|
|
1026
1602
|
}
|
|
1027
|
-
localState?.nativeProps?.set({ [key]: targetProp });
|
|
1028
1603
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
if (is.colorSpaceExist(texture) && is.colorSpaceExist(rootState.gl))
|
|
1039
|
-
texture.colorSpace = rootState.gl.outputColorSpace;
|
|
1040
|
-
else
|
|
1041
|
-
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();
|
|
1042
1613
|
}
|
|
1614
|
+
this.view = this.vcr.createEmbeddedView(this.template);
|
|
1615
|
+
safeDetectChanges(this.view);
|
|
1043
1616
|
}
|
|
1044
|
-
|
|
1045
|
-
}
|
|
1046
|
-
checkUpdate(targetProp);
|
|
1047
|
-
invalidateInstance(instance);
|
|
1048
|
-
}
|
|
1049
|
-
const instanceHandlers = localState.eventCount;
|
|
1050
|
-
const parent = localState.parent ? untracked(localState.parent) : null;
|
|
1051
|
-
if (parent && rootState.internal && instance['raycast'] && instanceHandlers !== localState.eventCount) {
|
|
1052
|
-
// Pre-emptively remove the instance from the interaction manager
|
|
1053
|
-
const index = rootState.internal.interaction.indexOf(instance);
|
|
1054
|
-
if (index > -1)
|
|
1055
|
-
rootState.internal.interaction.splice(index, 1);
|
|
1056
|
-
// Add the instance to the interaction manager only when it has handlers
|
|
1057
|
-
if (localState.eventCount)
|
|
1058
|
-
rootState.internal.interaction.push(instance);
|
|
1059
|
-
}
|
|
1060
|
-
if (parent && localState.afterUpdate && localState.afterUpdate.observed && changes.length) {
|
|
1061
|
-
localState.afterUpdate.emit(instance);
|
|
1617
|
+
});
|
|
1062
1618
|
}
|
|
1063
|
-
|
|
1619
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtCommonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1620
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.2", type: NgtCommonDirective, ngImport: i0 }); }
|
|
1064
1621
|
}
|
|
1622
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtCommonDirective, decorators: [{
|
|
1623
|
+
type: Directive
|
|
1624
|
+
}], ctorParameters: function () { return []; } });
|
|
1065
1625
|
|
|
1066
|
-
|
|
1067
|
-
const { invalidate, advance } = createLoop(rootStateMap);
|
|
1068
|
-
const shallowLoose = { objects: 'shallow', strict: false };
|
|
1069
|
-
class NgtStore extends NgtSignalStore {
|
|
1626
|
+
class NgtArgs extends NgtCommonDirective {
|
|
1070
1627
|
constructor() {
|
|
1071
1628
|
super(...arguments);
|
|
1072
|
-
this
|
|
1073
|
-
this.#window = inject(DOCUMENT).defaultView;
|
|
1074
|
-
this.#injector = inject(Injector);
|
|
1075
|
-
this.isInit = false;
|
|
1076
|
-
}
|
|
1077
|
-
#parentStore;
|
|
1078
|
-
#window;
|
|
1079
|
-
#injector;
|
|
1080
|
-
init() {
|
|
1081
|
-
if (!this.isInit) {
|
|
1082
|
-
const position = new THREE.Vector3();
|
|
1083
|
-
const defaultTarget = new THREE.Vector3();
|
|
1084
|
-
const tempTarget = new THREE.Vector3();
|
|
1085
|
-
const getCurrentViewport = (camera = this.get('camera'), target = defaultTarget, size = this.get('size')) => {
|
|
1086
|
-
const { width, height, top, left } = size;
|
|
1087
|
-
const aspect = width / height;
|
|
1088
|
-
if (target instanceof THREE.Vector3)
|
|
1089
|
-
tempTarget.copy(target);
|
|
1090
|
-
else
|
|
1091
|
-
tempTarget.set(...target);
|
|
1092
|
-
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
1093
|
-
if (is.orthographicCamera(camera)) {
|
|
1094
|
-
return {
|
|
1095
|
-
width: width / camera.zoom,
|
|
1096
|
-
height: height / camera.zoom,
|
|
1097
|
-
top,
|
|
1098
|
-
left,
|
|
1099
|
-
factor: 1,
|
|
1100
|
-
distance,
|
|
1101
|
-
aspect,
|
|
1102
|
-
};
|
|
1103
|
-
}
|
|
1104
|
-
const fov = (camera.fov * Math.PI) / 180; // convert vertical fov to radians
|
|
1105
|
-
const h = 2 * Math.tan(fov / 2) * distance; // visible height
|
|
1106
|
-
const w = h * aspect;
|
|
1107
|
-
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
1108
|
-
};
|
|
1109
|
-
let performanceTimeout;
|
|
1110
|
-
const setPerformanceCurrent = (current) => {
|
|
1111
|
-
this.set((state) => ({ performance: { ...state.performance, current } }));
|
|
1112
|
-
};
|
|
1113
|
-
this.set({
|
|
1114
|
-
get: this.get.bind(this),
|
|
1115
|
-
set: this.set.bind(this),
|
|
1116
|
-
ready: false,
|
|
1117
|
-
events: { priority: 1, enabled: true, connected: false },
|
|
1118
|
-
invalidate: (frames = 1) => invalidate(this, frames),
|
|
1119
|
-
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, this),
|
|
1120
|
-
legacy: false,
|
|
1121
|
-
linear: false,
|
|
1122
|
-
flat: false,
|
|
1123
|
-
controls: null,
|
|
1124
|
-
clock: new THREE.Clock(),
|
|
1125
|
-
pointer: new THREE.Vector2(),
|
|
1126
|
-
frameloop: 'always',
|
|
1127
|
-
performance: {
|
|
1128
|
-
current: 1,
|
|
1129
|
-
min: 0.5,
|
|
1130
|
-
max: 1,
|
|
1131
|
-
debounce: 200,
|
|
1132
|
-
regress: () => {
|
|
1133
|
-
const state = this.get();
|
|
1134
|
-
// clear timeout
|
|
1135
|
-
if (performanceTimeout)
|
|
1136
|
-
clearTimeout(performanceTimeout);
|
|
1137
|
-
// set lower bound
|
|
1138
|
-
if (state.performance.current !== state.performance.min)
|
|
1139
|
-
setPerformanceCurrent(state.performance.min);
|
|
1140
|
-
// go back to upper bound
|
|
1141
|
-
performanceTimeout = setTimeout(() => {
|
|
1142
|
-
setPerformanceCurrent(this.get('performance', 'max') || 1);
|
|
1143
|
-
}, state.performance.debounce);
|
|
1144
|
-
},
|
|
1145
|
-
},
|
|
1146
|
-
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
1147
|
-
viewport: {
|
|
1148
|
-
initialDpr: 0,
|
|
1149
|
-
dpr: 0,
|
|
1150
|
-
width: 0,
|
|
1151
|
-
height: 0,
|
|
1152
|
-
top: 0,
|
|
1153
|
-
left: 0,
|
|
1154
|
-
aspect: 0,
|
|
1155
|
-
distance: 0,
|
|
1156
|
-
factor: 0,
|
|
1157
|
-
getCurrentViewport,
|
|
1158
|
-
},
|
|
1159
|
-
previousStore: this.#parentStore,
|
|
1160
|
-
internal: {
|
|
1161
|
-
active: false,
|
|
1162
|
-
priority: 0,
|
|
1163
|
-
frames: 0,
|
|
1164
|
-
lastEvent: new ElementRef(null),
|
|
1165
|
-
interaction: [],
|
|
1166
|
-
hovered: new Map(),
|
|
1167
|
-
subscribers: [],
|
|
1168
|
-
initialClick: [0, 0],
|
|
1169
|
-
initialHits: [],
|
|
1170
|
-
capturedMap: new Map(),
|
|
1171
|
-
subscribe: (callback, priority = 0, store = this) => {
|
|
1172
|
-
const internal = this.get('internal');
|
|
1173
|
-
// If this subscription was given a priority, it takes rendering into its own hands
|
|
1174
|
-
// For that reason we switch off automatic rendering and increase the manual flag
|
|
1175
|
-
// As long as this flag is positive there can be no internal rendering at all
|
|
1176
|
-
// because there could be multiple render subscriptions
|
|
1177
|
-
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1178
|
-
internal.subscribers.push({ priority, store, callback });
|
|
1179
|
-
// Register subscriber and sort layers from lowest to highest, meaning,
|
|
1180
|
-
// highest priority renders last (on top of the other frames)
|
|
1181
|
-
internal.subscribers.sort((a, b) => (a.priority || 0) - (b.priority || 0));
|
|
1182
|
-
return () => {
|
|
1183
|
-
const internal = this.get('internal');
|
|
1184
|
-
if (internal?.subscribers) {
|
|
1185
|
-
// Decrease manual flag if this subscription had a priority
|
|
1186
|
-
internal.priority = internal.priority - (priority > 0 ? 1 : 0);
|
|
1187
|
-
// Remove subscriber from list
|
|
1188
|
-
internal.subscribers = internal.subscribers.filter((s) => s.callback !== callback);
|
|
1189
|
-
}
|
|
1190
|
-
};
|
|
1191
|
-
},
|
|
1192
|
-
},
|
|
1193
|
-
setEvents: (events) => {
|
|
1194
|
-
this.set((state) => ({ events: { ...state.events, ...events } }));
|
|
1195
|
-
},
|
|
1196
|
-
setSize: (width, height, top, left) => {
|
|
1197
|
-
const camera = this.get('camera');
|
|
1198
|
-
const size = { width, height, top: top || 0, left: left || 0 };
|
|
1199
|
-
this.set((state) => ({
|
|
1200
|
-
size,
|
|
1201
|
-
viewport: { ...state.viewport, ...getCurrentViewport(camera, defaultTarget, size) },
|
|
1202
|
-
}));
|
|
1203
|
-
},
|
|
1204
|
-
setDpr: (dpr) => {
|
|
1205
|
-
const resolved = makeDpr(dpr, this.#window);
|
|
1206
|
-
this.set((state) => ({
|
|
1207
|
-
viewport: {
|
|
1208
|
-
...state.viewport,
|
|
1209
|
-
dpr: resolved,
|
|
1210
|
-
initialDpr: state.viewport.initialDpr || resolved,
|
|
1211
|
-
},
|
|
1212
|
-
}));
|
|
1213
|
-
},
|
|
1214
|
-
setFrameloop: (frameloop = 'always') => {
|
|
1215
|
-
const clock = this.get('clock');
|
|
1216
|
-
clock.stop();
|
|
1217
|
-
clock.elapsedTime = 0;
|
|
1218
|
-
if (frameloop !== 'never') {
|
|
1219
|
-
clock.start();
|
|
1220
|
-
clock.elapsedTime = 0;
|
|
1221
|
-
}
|
|
1222
|
-
this.set({ frameloop });
|
|
1223
|
-
},
|
|
1224
|
-
});
|
|
1225
|
-
this.isInit = true;
|
|
1226
|
-
this.#resize();
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
configure(inputs, canvasElement) {
|
|
1230
|
-
const { gl: glOptions, size: sizeOptions, camera: cameraOptions, raycaster: raycasterOptions, scene: sceneOptions, events, orthographic, lookAt, shadows, linear, legacy, flat, dpr, frameloop, performance, } = inputs;
|
|
1231
|
-
const state = this.get();
|
|
1232
|
-
const stateToUpdate = {};
|
|
1233
|
-
// setup renderer
|
|
1234
|
-
let gl = state.gl;
|
|
1235
|
-
if (!state.gl)
|
|
1236
|
-
stateToUpdate.gl = gl = makeDefaultRenderer(glOptions, canvasElement);
|
|
1237
|
-
// setup raycaster
|
|
1238
|
-
let raycaster = state.raycaster;
|
|
1239
|
-
if (!raycaster)
|
|
1240
|
-
stateToUpdate.raycaster = raycaster = new THREE.Raycaster();
|
|
1241
|
-
// set raycaster options
|
|
1242
|
-
const { params, ...options } = raycasterOptions || {};
|
|
1243
|
-
if (!is.equ(options, raycaster, shallowLoose))
|
|
1244
|
-
applyProps(raycaster, { ...options });
|
|
1245
|
-
if (!is.equ(params, raycaster.params, shallowLoose)) {
|
|
1246
|
-
applyProps(raycaster, { params: { ...raycaster.params, ...(params || {}) } });
|
|
1247
|
-
}
|
|
1248
|
-
// create default camera
|
|
1249
|
-
if (!state.camera) {
|
|
1250
|
-
const isCamera = is.camera(cameraOptions);
|
|
1251
|
-
let camera = isCamera ? cameraOptions : makeDefaultCamera(orthographic || false, state.size);
|
|
1252
|
-
if (!isCamera) {
|
|
1253
|
-
if (cameraOptions)
|
|
1254
|
-
applyProps(camera, cameraOptions);
|
|
1255
|
-
// set position.z
|
|
1256
|
-
if (!cameraOptions?.position)
|
|
1257
|
-
camera.position.z = 5;
|
|
1258
|
-
// always look at center or passed-in lookAt by default
|
|
1259
|
-
if (!cameraOptions?.rotation && !cameraOptions?.quaternion) {
|
|
1260
|
-
if (Array.isArray(lookAt))
|
|
1261
|
-
camera.lookAt(lookAt[0], lookAt[1], lookAt[2]);
|
|
1262
|
-
else if (lookAt instanceof THREE.Vector3)
|
|
1263
|
-
camera.lookAt(lookAt);
|
|
1264
|
-
else
|
|
1265
|
-
camera.lookAt(0, 0, 0);
|
|
1266
|
-
}
|
|
1267
|
-
// update projection matrix after applyprops
|
|
1268
|
-
camera.updateProjectionMatrix?.();
|
|
1269
|
-
}
|
|
1270
|
-
if (!is.instance(camera))
|
|
1271
|
-
camera = prepare(camera, { store: this });
|
|
1272
|
-
stateToUpdate.camera = camera;
|
|
1273
|
-
}
|
|
1274
|
-
// Set up scene (one time only!)
|
|
1275
|
-
if (!state.scene) {
|
|
1276
|
-
let scene;
|
|
1277
|
-
if (sceneOptions instanceof THREE.Scene) {
|
|
1278
|
-
scene = prepare(sceneOptions, { store: this });
|
|
1279
|
-
}
|
|
1280
|
-
else {
|
|
1281
|
-
scene = prepare(new THREE.Scene(), { store: this });
|
|
1282
|
-
if (sceneOptions)
|
|
1283
|
-
applyProps(scene, sceneOptions);
|
|
1284
|
-
}
|
|
1285
|
-
stateToUpdate.scene = scene;
|
|
1286
|
-
}
|
|
1287
|
-
// Set up XR (one time only!)
|
|
1288
|
-
if (!state.xr) {
|
|
1289
|
-
// Handle frame behavior in WebXR
|
|
1290
|
-
const handleXRFrame = (timestamp, frame) => {
|
|
1291
|
-
const state = this.get();
|
|
1292
|
-
if (state.frameloop === 'never')
|
|
1293
|
-
return;
|
|
1294
|
-
advance(timestamp, true, this, frame);
|
|
1295
|
-
};
|
|
1296
|
-
// Toggle render switching on session
|
|
1297
|
-
const handleSessionChange = () => {
|
|
1298
|
-
const state = this.get();
|
|
1299
|
-
state.gl.xr.enabled = state.gl.xr.isPresenting;
|
|
1300
|
-
state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
|
|
1301
|
-
if (!state.gl.xr.isPresenting)
|
|
1302
|
-
state.invalidate();
|
|
1303
|
-
};
|
|
1304
|
-
// WebXR session manager
|
|
1305
|
-
const xr = {
|
|
1306
|
-
connect: () => {
|
|
1307
|
-
gl.xr.addEventListener('sessionstart', handleSessionChange);
|
|
1308
|
-
gl.xr.addEventListener('sessionend', handleSessionChange);
|
|
1309
|
-
},
|
|
1310
|
-
disconnect: () => {
|
|
1311
|
-
gl.xr.removeEventListener('sessionstart', handleSessionChange);
|
|
1312
|
-
gl.xr.removeEventListener('sessionend', handleSessionChange);
|
|
1313
|
-
},
|
|
1314
|
-
};
|
|
1315
|
-
// Subscribe to WebXR session events
|
|
1316
|
-
if (gl.xr)
|
|
1317
|
-
xr.connect();
|
|
1318
|
-
stateToUpdate.xr = xr;
|
|
1319
|
-
}
|
|
1320
|
-
// Set shadowmap
|
|
1321
|
-
if (gl.shadowMap) {
|
|
1322
|
-
const oldEnabled = gl.shadowMap.enabled;
|
|
1323
|
-
const oldType = gl.shadowMap.type;
|
|
1324
|
-
gl.shadowMap.enabled = !!shadows;
|
|
1325
|
-
if (typeof shadows === 'boolean') {
|
|
1326
|
-
gl.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
1327
|
-
}
|
|
1328
|
-
else if (typeof shadows === 'string') {
|
|
1329
|
-
const types = {
|
|
1330
|
-
basic: THREE.BasicShadowMap,
|
|
1331
|
-
percentage: THREE.PCFShadowMap,
|
|
1332
|
-
soft: THREE.PCFSoftShadowMap,
|
|
1333
|
-
variance: THREE.VSMShadowMap,
|
|
1334
|
-
};
|
|
1335
|
-
gl.shadowMap.type = types[shadows] ?? THREE.PCFSoftShadowMap;
|
|
1336
|
-
}
|
|
1337
|
-
else if (is.obj(shadows)) {
|
|
1338
|
-
Object.assign(gl.shadowMap, shadows);
|
|
1339
|
-
}
|
|
1340
|
-
if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type)
|
|
1341
|
-
checkNeedsUpdate(gl.shadowMap);
|
|
1342
|
-
}
|
|
1343
|
-
// Safely set color management if available.
|
|
1344
|
-
// Avoid accessing THREE.ColorManagement to play nice with older versions
|
|
1345
|
-
if (THREE.ColorManagement) {
|
|
1346
|
-
const ColorManagement = THREE.ColorManagement;
|
|
1347
|
-
if ('enabled' in ColorManagement)
|
|
1348
|
-
ColorManagement['enabled'] = !legacy ?? false;
|
|
1349
|
-
else if ('legacyMode' in ColorManagement)
|
|
1350
|
-
ColorManagement['legacyMode'] = legacy ?? true;
|
|
1351
|
-
}
|
|
1352
|
-
// set color space and tonemapping preferences
|
|
1353
|
-
const LinearEncoding = 3000;
|
|
1354
|
-
const sRGBEncoding = 3001;
|
|
1355
|
-
applyProps(gl, {
|
|
1356
|
-
outputEncoding: linear ? LinearEncoding : sRGBEncoding,
|
|
1357
|
-
toneMapping: flat ? THREE.NoToneMapping : THREE.ACESFilmicToneMapping,
|
|
1358
|
-
});
|
|
1359
|
-
// Update color management state
|
|
1360
|
-
if (state.legacy !== legacy)
|
|
1361
|
-
stateToUpdate.legacy = legacy;
|
|
1362
|
-
if (state.linear !== linear)
|
|
1363
|
-
stateToUpdate.linear = linear;
|
|
1364
|
-
if (state.flat !== flat)
|
|
1365
|
-
stateToUpdate.flat = flat;
|
|
1366
|
-
// Set gl props
|
|
1367
|
-
gl.setClearAlpha(0);
|
|
1368
|
-
gl.setPixelRatio(makeDpr(state.viewport.dpr));
|
|
1369
|
-
gl.setSize(state.size.width, state.size.height);
|
|
1370
|
-
if (is.obj(glOptions) &&
|
|
1371
|
-
!(typeof glOptions === 'function') &&
|
|
1372
|
-
!is.renderer(glOptions) &&
|
|
1373
|
-
!is.equ(glOptions, gl, shallowLoose)) {
|
|
1374
|
-
applyProps(gl, glOptions);
|
|
1375
|
-
}
|
|
1376
|
-
// Store events internally
|
|
1377
|
-
if (events && !state.events.handlers)
|
|
1378
|
-
stateToUpdate.events = events(this);
|
|
1379
|
-
// Check performance
|
|
1380
|
-
if (performance && !is.equ(performance, state.performance, shallowLoose)) {
|
|
1381
|
-
stateToUpdate.performance = { ...state.performance, ...performance };
|
|
1382
|
-
}
|
|
1383
|
-
this.set(stateToUpdate);
|
|
1384
|
-
// Check pixelratio
|
|
1385
|
-
if (dpr && state.viewport.dpr !== makeDpr(dpr))
|
|
1386
|
-
state.setDpr(dpr);
|
|
1387
|
-
// Check size, allow it to take on container bounds initially
|
|
1388
|
-
const size = computeInitialSize(canvasElement, sizeOptions);
|
|
1389
|
-
if (!is.equ(size, state.size, shallowLoose))
|
|
1390
|
-
state.setSize(size.width, size.height, size.top, size.left);
|
|
1391
|
-
// Check frameloop
|
|
1392
|
-
if (state.frameloop !== frameloop)
|
|
1393
|
-
state.setFrameloop(frameloop);
|
|
1394
|
-
if (!this.get('ready'))
|
|
1395
|
-
this.set({ ready: true });
|
|
1396
|
-
this.#invalidate();
|
|
1397
|
-
}
|
|
1398
|
-
destroy(canvas) {
|
|
1399
|
-
this.set((state) => ({ internal: { ...state.internal, active: false } }));
|
|
1400
|
-
setTimeout(() => {
|
|
1401
|
-
const { gl, xr, events } = this.get();
|
|
1402
|
-
if (gl) {
|
|
1403
|
-
if (events.disconnect) {
|
|
1404
|
-
events.disconnect();
|
|
1405
|
-
}
|
|
1406
|
-
gl.renderLists.dispose();
|
|
1407
|
-
gl.forceContextLoss();
|
|
1408
|
-
if (gl.xr && gl.xr.enabled) {
|
|
1409
|
-
gl.xr.setAnimationLoop(null);
|
|
1410
|
-
xr.disconnect();
|
|
1411
|
-
}
|
|
1412
|
-
dispose(this.get());
|
|
1413
|
-
rootStateMap.delete(canvas);
|
|
1414
|
-
}
|
|
1415
|
-
}, 500);
|
|
1629
|
+
this.injectedArgs = [];
|
|
1416
1630
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
const size = this.select('size');
|
|
1424
|
-
const viewport = this.select('viewport');
|
|
1425
|
-
const triggers = computed(() => ({ camera: camera(), size: size(), viewport: viewport(), gl: this.get('gl') }));
|
|
1426
|
-
effect(() => {
|
|
1427
|
-
const { camera, size, viewport, gl } = triggers();
|
|
1428
|
-
// resize camera and renderer on changes to size and dpr
|
|
1429
|
-
if (size !== oldSize || viewport.dpr !== oldDpr) {
|
|
1430
|
-
oldSize = size;
|
|
1431
|
-
oldDpr = viewport.dpr;
|
|
1432
|
-
// update camera
|
|
1433
|
-
updateCamera(camera, size);
|
|
1434
|
-
gl.setPixelRatio(viewport.dpr);
|
|
1435
|
-
gl.setSize(size.width, size.height);
|
|
1436
|
-
}
|
|
1437
|
-
// update viewport when camera changes
|
|
1438
|
-
if (camera !== oldCamera) {
|
|
1439
|
-
oldCamera = camera;
|
|
1440
|
-
updateCamera(camera, size);
|
|
1441
|
-
this.set((state) => ({
|
|
1442
|
-
viewport: { ...state.viewport, ...state.viewport.getCurrentViewport(camera) },
|
|
1443
|
-
}));
|
|
1444
|
-
}
|
|
1445
|
-
}, { 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();
|
|
1446
1637
|
}
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
}
|
|
1638
|
+
get args() {
|
|
1639
|
+
if (this.validate()) {
|
|
1640
|
+
this.injected = true;
|
|
1641
|
+
return this.injectedArgs;
|
|
1642
|
+
}
|
|
1643
|
+
return null;
|
|
1452
1644
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
}
|
|
1456
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtStore, decorators: [{
|
|
1457
|
-
type: Injectable
|
|
1458
|
-
}] });
|
|
1459
|
-
function computeInitialSize(canvas, defaultSize) {
|
|
1460
|
-
if (defaultSize)
|
|
1461
|
-
return defaultSize;
|
|
1462
|
-
if (canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
1463
|
-
return canvas.parentElement.getBoundingClientRect();
|
|
1645
|
+
validate() {
|
|
1646
|
+
return !this.injected && !!this.injectedArgs.length;
|
|
1464
1647
|
}
|
|
1465
|
-
|
|
1648
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtArgs, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1649
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.2", type: NgtArgs, isStandalone: true, selector: "ng-template[args]", inputs: { args: "args" }, usesInheritance: true, ngImport: i0 }); }
|
|
1466
1650
|
}
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1651
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", 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;
|
|
1662
|
+
}
|
|
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;
|
|
1474
1676
|
}
|
|
1677
|
+
validate() {
|
|
1678
|
+
return !this.injected && !!this.injectedParent;
|
|
1679
|
+
}
|
|
1680
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtParent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1681
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.2", type: NgtParent, isStandalone: true, selector: "ng-template[parent]", inputs: { parent: "parent" }, usesInheritance: true, ngImport: i0 }); }
|
|
1475
1682
|
}
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
}
|
|
1483
|
-
const NGT_CATALOGUE = new InjectionToken('THREE Constructors Catalogue', { factory: () => catalogue });
|
|
1683
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtParent, decorators: [{
|
|
1684
|
+
type: Directive,
|
|
1685
|
+
args: [{ selector: 'ng-template[parent]', standalone: true }]
|
|
1686
|
+
}], propDecorators: { parent: [{
|
|
1687
|
+
type: Input
|
|
1688
|
+
}] } });
|
|
1484
1689
|
|
|
1485
1690
|
function attach(object, value, paths = []) {
|
|
1486
1691
|
const [base, ...remaining] = paths;
|
|
@@ -1512,25 +1717,38 @@ function createAttachFunction(cb) {
|
|
|
1512
1717
|
return (parent, child, store) => cb({ parent, child, store });
|
|
1513
1718
|
}
|
|
1514
1719
|
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
};
|
|
1720
|
+
// @internal
|
|
1721
|
+
var NgtRendererClassId;
|
|
1722
|
+
(function (NgtRendererClassId) {
|
|
1723
|
+
NgtRendererClassId[NgtRendererClassId["type"] = 0] = "type";
|
|
1724
|
+
NgtRendererClassId[NgtRendererClassId["parent"] = 1] = "parent";
|
|
1725
|
+
NgtRendererClassId[NgtRendererClassId["injectedParent"] = 2] = "injectedParent";
|
|
1726
|
+
NgtRendererClassId[NgtRendererClassId["children"] = 3] = "children";
|
|
1727
|
+
NgtRendererClassId[NgtRendererClassId["destroyed"] = 4] = "destroyed";
|
|
1728
|
+
NgtRendererClassId[NgtRendererClassId["compound"] = 5] = "compound";
|
|
1729
|
+
NgtRendererClassId[NgtRendererClassId["compoundParent"] = 6] = "compoundParent";
|
|
1730
|
+
NgtRendererClassId[NgtRendererClassId["compounded"] = 7] = "compounded";
|
|
1731
|
+
NgtRendererClassId[NgtRendererClassId["queueOps"] = 8] = "queueOps";
|
|
1732
|
+
NgtRendererClassId[NgtRendererClassId["attributes"] = 9] = "attributes";
|
|
1733
|
+
NgtRendererClassId[NgtRendererClassId["properties"] = 10] = "properties";
|
|
1734
|
+
NgtRendererClassId[NgtRendererClassId["rawValue"] = 11] = "rawValue";
|
|
1735
|
+
NgtRendererClassId[NgtRendererClassId["ref"] = 12] = "ref";
|
|
1736
|
+
NgtRendererClassId[NgtRendererClassId["portalContainer"] = 13] = "portalContainer";
|
|
1737
|
+
NgtRendererClassId[NgtRendererClassId["injectorFactory"] = 14] = "injectorFactory";
|
|
1738
|
+
})(NgtRendererClassId || (NgtRendererClassId = {}));
|
|
1739
|
+
// @internal
|
|
1740
|
+
var NgtCompoundClassId;
|
|
1741
|
+
(function (NgtCompoundClassId) {
|
|
1742
|
+
NgtCompoundClassId[NgtCompoundClassId["applyFirst"] = 0] = "applyFirst";
|
|
1743
|
+
NgtCompoundClassId[NgtCompoundClassId["props"] = 1] = "props";
|
|
1744
|
+
})(NgtCompoundClassId || (NgtCompoundClassId = {}));
|
|
1745
|
+
// @internal
|
|
1746
|
+
var NgtQueueOpClassId;
|
|
1747
|
+
(function (NgtQueueOpClassId) {
|
|
1748
|
+
NgtQueueOpClassId[NgtQueueOpClassId["type"] = 0] = "type";
|
|
1749
|
+
NgtQueueOpClassId[NgtQueueOpClassId["op"] = 1] = "op";
|
|
1750
|
+
NgtQueueOpClassId[NgtQueueOpClassId["done"] = 2] = "done";
|
|
1751
|
+
})(NgtQueueOpClassId || (NgtQueueOpClassId = {}));
|
|
1534
1752
|
function attachThreeChild(parent, child) {
|
|
1535
1753
|
const pLS = getLocalState(parent);
|
|
1536
1754
|
const cLS = getLocalState(child);
|
|
@@ -1541,7 +1759,7 @@ function attachThreeChild(parent, child) {
|
|
|
1541
1759
|
let added = false;
|
|
1542
1760
|
// assign store on child if not already exist
|
|
1543
1761
|
// or child store is the parent of parent store
|
|
1544
|
-
if (!cLS.store || cLS.store === pLS.store.get('
|
|
1762
|
+
if (!cLS.store || cLS.store === pLS.store.get('previousRoot')) {
|
|
1545
1763
|
cLS.store = pLS.store;
|
|
1546
1764
|
}
|
|
1547
1765
|
if (cLS.attach) {
|
|
@@ -1567,13 +1785,15 @@ function attachThreeChild(parent, child) {
|
|
|
1567
1785
|
}
|
|
1568
1786
|
// attach
|
|
1569
1787
|
if (cLS.isRaw) {
|
|
1570
|
-
if (cLS.parent) {
|
|
1571
|
-
|
|
1788
|
+
if (cLS.parent && cLS.parent() !== parent) {
|
|
1789
|
+
untracked(() => {
|
|
1790
|
+
cLS.parent.set(parent);
|
|
1791
|
+
});
|
|
1572
1792
|
}
|
|
1573
1793
|
// at this point we don't have rawValue yet, so we bail and wait until the Renderer recalls attach
|
|
1574
|
-
if (child.__ngt_renderer__[
|
|
1794
|
+
if (child.__ngt_renderer__[NgtRendererClassId.rawValue] === undefined)
|
|
1575
1795
|
return;
|
|
1576
|
-
attach(parent, child.__ngt_renderer__[
|
|
1796
|
+
attach(parent, child.__ngt_renderer__[NgtRendererClassId.rawValue], attachProp);
|
|
1577
1797
|
}
|
|
1578
1798
|
else {
|
|
1579
1799
|
attach(parent, child, attachProp);
|
|
@@ -1587,8 +1807,10 @@ function attachThreeChild(parent, child) {
|
|
|
1587
1807
|
added = true;
|
|
1588
1808
|
}
|
|
1589
1809
|
pLS.add(child, added ? 'objects' : 'nonObjects');
|
|
1590
|
-
if (cLS.parent) {
|
|
1591
|
-
|
|
1810
|
+
if (cLS.parent && cLS.parent() !== parent) {
|
|
1811
|
+
untracked(() => {
|
|
1812
|
+
cLS.parent.set(parent);
|
|
1813
|
+
});
|
|
1592
1814
|
}
|
|
1593
1815
|
if (cLS.afterAttach)
|
|
1594
1816
|
cLS.afterAttach.emit({ parent, node: child });
|
|
@@ -1599,11 +1821,13 @@ function removeThreeChild(parent, child, dispose) {
|
|
|
1599
1821
|
const pLS = getLocalState(parent);
|
|
1600
1822
|
const cLS = getLocalState(child);
|
|
1601
1823
|
// clear parent ref
|
|
1602
|
-
|
|
1824
|
+
untracked(() => {
|
|
1825
|
+
cLS.parent?.set(null);
|
|
1826
|
+
});
|
|
1603
1827
|
// remove child from parent
|
|
1604
|
-
if (untracked(pLS.objects))
|
|
1828
|
+
if (pLS.objects && untracked(pLS.objects))
|
|
1605
1829
|
pLS.remove(child, 'objects');
|
|
1606
|
-
if (untracked(pLS.nonObjects))
|
|
1830
|
+
if (pLS.nonObjects && untracked(pLS.nonObjects))
|
|
1607
1831
|
pLS.remove(child, 'nonObjects');
|
|
1608
1832
|
if (cLS.attach) {
|
|
1609
1833
|
detach(parent, child, cLS.attach);
|
|
@@ -1627,7 +1851,15 @@ function removeThreeRecursive(array, parent, dispose) {
|
|
|
1627
1851
|
if (array)
|
|
1628
1852
|
[...array].forEach((child) => removeThreeChild(parent, child, dispose));
|
|
1629
1853
|
}
|
|
1630
|
-
function
|
|
1854
|
+
function kebabToPascal(str) {
|
|
1855
|
+
// split the string at each hyphen
|
|
1856
|
+
const parts = str.split('-');
|
|
1857
|
+
// map over the parts, capitalizing the first letter of each part
|
|
1858
|
+
const pascalParts = parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1));
|
|
1859
|
+
// join the parts together to create the final PascalCase string
|
|
1860
|
+
return pascalParts.join('');
|
|
1861
|
+
}
|
|
1862
|
+
function processThreeEvent(instance, priority, eventName, callback, zone, rootCdr, targetCdr) {
|
|
1631
1863
|
const lS = getLocalState(instance);
|
|
1632
1864
|
if (eventName === SPECIAL_EVENTS.BEFORE_RENDER) {
|
|
1633
1865
|
return lS.store
|
|
@@ -1651,8 +1883,7 @@ function processThreeEvent(instance, priority, eventName, callback, zone, cdr, t
|
|
|
1651
1883
|
previousHandler(event);
|
|
1652
1884
|
zone.run(() => {
|
|
1653
1885
|
callback(event);
|
|
1654
|
-
safeDetectChanges(targetCdr);
|
|
1655
|
-
safeDetectChanges(cdr);
|
|
1886
|
+
safeDetectChanges(targetCdr, rootCdr);
|
|
1656
1887
|
});
|
|
1657
1888
|
};
|
|
1658
1889
|
Object.assign(lS.handlers, { [eventName]: updatedCallback });
|
|
@@ -1666,6 +1897,7 @@ function processThreeEvent(instance, priority, eventName, callback, zone, cdr, t
|
|
|
1666
1897
|
return () => {
|
|
1667
1898
|
const localState = getLocalState(instance);
|
|
1668
1899
|
if (localState && localState.eventCount) {
|
|
1900
|
+
localState.eventCount -= 1;
|
|
1669
1901
|
const index = localState.store
|
|
1670
1902
|
.get('internal', 'interaction')
|
|
1671
1903
|
.findIndex((obj) => obj.uuid === instance.uuid);
|
|
@@ -1674,117 +1906,12 @@ function processThreeEvent(instance, priority, eventName, callback, zone, cdr, t
|
|
|
1674
1906
|
}
|
|
1675
1907
|
};
|
|
1676
1908
|
}
|
|
1677
|
-
function eventToHandler(callback) {
|
|
1678
|
-
return (event) => {
|
|
1679
|
-
callback(event);
|
|
1680
|
-
};
|
|
1681
|
-
}
|
|
1682
|
-
function kebabToPascal(str) {
|
|
1683
|
-
// split the string at each hyphen
|
|
1684
|
-
const parts = str.split('-');
|
|
1685
|
-
// map over the parts, capitalizing the first letter of each part
|
|
1686
|
-
const pascalParts = parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1));
|
|
1687
|
-
// join the parts together to create the final PascalCase string
|
|
1688
|
-
return pascalParts.join('');
|
|
1689
|
-
}
|
|
1690
|
-
|
|
1691
|
-
class NgtCommonDirective {
|
|
1692
|
-
#vcr;
|
|
1693
|
-
#zone;
|
|
1694
|
-
#template;
|
|
1695
|
-
#view;
|
|
1696
|
-
constructor() {
|
|
1697
|
-
this.#vcr = inject(ViewContainerRef);
|
|
1698
|
-
this.#zone = inject(NgZone);
|
|
1699
|
-
this.#template = inject(TemplateRef);
|
|
1700
|
-
this.injected = false;
|
|
1701
|
-
this.shouldCreateView = true;
|
|
1702
|
-
const commentNode = this.#vcr.element.nativeElement;
|
|
1703
|
-
if (commentNode[SPECIAL_INTERNAL_ADD_COMMENT]) {
|
|
1704
|
-
commentNode[SPECIAL_INTERNAL_ADD_COMMENT]();
|
|
1705
|
-
delete commentNode[SPECIAL_INTERNAL_ADD_COMMENT];
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
createView() {
|
|
1709
|
-
if (this.shouldCreateView) {
|
|
1710
|
-
if (this.#view && !this.#view.destroyed) {
|
|
1711
|
-
this.#view.destroy();
|
|
1712
|
-
}
|
|
1713
|
-
this.#zone.runOutsideAngular(() => {
|
|
1714
|
-
this.#view = this.#vcr.createEmbeddedView(this.#template);
|
|
1715
|
-
this.#view.detectChanges();
|
|
1716
|
-
});
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtCommonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1720
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtCommonDirective, ngImport: i0 }); }
|
|
1721
|
-
}
|
|
1722
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtCommonDirective, decorators: [{
|
|
1723
|
-
type: Directive
|
|
1724
|
-
}], ctorParameters: function () { return []; } });
|
|
1725
|
-
|
|
1726
|
-
class NgtArgs extends NgtCommonDirective {
|
|
1727
|
-
#injectedArgs = [];
|
|
1728
|
-
set args(args) {
|
|
1729
|
-
if (args == null || !Array.isArray(args) || (args.length === 1 && args[0] === null))
|
|
1730
|
-
return;
|
|
1731
|
-
this.injected = false;
|
|
1732
|
-
this.#injectedArgs = args;
|
|
1733
|
-
this.createView();
|
|
1734
|
-
}
|
|
1735
|
-
get args() {
|
|
1736
|
-
if (this.validate()) {
|
|
1737
|
-
this.injected = true;
|
|
1738
|
-
return this.#injectedArgs;
|
|
1739
|
-
}
|
|
1740
|
-
return null;
|
|
1741
|
-
}
|
|
1742
|
-
validate() {
|
|
1743
|
-
return !this.injected && !!this.#injectedArgs.length;
|
|
1744
|
-
}
|
|
1745
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtArgs, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1746
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtArgs, isStandalone: true, selector: "[args]", inputs: { args: "args" }, usesInheritance: true, ngImport: i0 }); }
|
|
1747
|
-
}
|
|
1748
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtArgs, decorators: [{
|
|
1749
|
-
type: Directive,
|
|
1750
|
-
args: [{ selector: '[args]', standalone: true }]
|
|
1751
|
-
}], propDecorators: { args: [{
|
|
1752
|
-
type: Input
|
|
1753
|
-
}] } });
|
|
1754
|
-
|
|
1755
|
-
class NgtParent extends NgtCommonDirective {
|
|
1756
|
-
#injectedParent = null;
|
|
1757
|
-
set parent(parent) {
|
|
1758
|
-
if (!parent)
|
|
1759
|
-
return;
|
|
1760
|
-
this.injected = false;
|
|
1761
|
-
this.#injectedParent = parent;
|
|
1762
|
-
this.createView();
|
|
1763
|
-
}
|
|
1764
|
-
get parent() {
|
|
1765
|
-
if (this.validate()) {
|
|
1766
|
-
this.injected = true;
|
|
1767
|
-
return this.#injectedParent;
|
|
1768
|
-
}
|
|
1769
|
-
return null;
|
|
1770
|
-
}
|
|
1771
|
-
validate() {
|
|
1772
|
-
return !this.injected && !!this.#injectedParent;
|
|
1773
|
-
}
|
|
1774
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtParent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1775
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtParent, isStandalone: true, selector: "[parent]", inputs: { parent: "parent" }, usesInheritance: true, ngImport: i0 }); }
|
|
1776
|
-
}
|
|
1777
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtParent, decorators: [{
|
|
1778
|
-
type: Directive,
|
|
1779
|
-
args: [{ selector: '[parent]', standalone: true }]
|
|
1780
|
-
}], propDecorators: { parent: [{
|
|
1781
|
-
type: Input
|
|
1782
|
-
}] } });
|
|
1783
1909
|
|
|
1910
|
+
const NGT_COMPOUND_PREFIXES = new InjectionToken('NgtCompoundPrefixes');
|
|
1784
1911
|
class NgtRendererStore {
|
|
1785
|
-
#comments = [];
|
|
1786
1912
|
constructor(root) {
|
|
1787
1913
|
this.root = root;
|
|
1914
|
+
this.comments = [];
|
|
1788
1915
|
}
|
|
1789
1916
|
createNode(type, node) {
|
|
1790
1917
|
const state = [
|
|
@@ -1805,99 +1932,108 @@ class NgtRendererStore {
|
|
|
1805
1932
|
undefined,
|
|
1806
1933
|
];
|
|
1807
1934
|
const rendererNode = Object.assign(node, { __ngt_renderer__: state });
|
|
1808
|
-
// assign ownerDocument to node so we can use HostListener in Component
|
|
1935
|
+
// NOTE: assign ownerDocument to node so we can use HostListener in Component
|
|
1809
1936
|
if (!rendererNode['ownerDocument'])
|
|
1810
1937
|
rendererNode['ownerDocument'] = this.root.document;
|
|
1811
|
-
// assign injectorFactory on non-three type since
|
|
1938
|
+
// NOTE: assign injectorFactory on non-three type since
|
|
1812
1939
|
// rendererNode is an instance of DOM Node
|
|
1813
|
-
if (state[
|
|
1814
|
-
state[
|
|
1940
|
+
if (state[NgtRendererClassId.type] !== 'three') {
|
|
1941
|
+
state[NgtRendererClassId.injectorFactory] = () => getDebugNode(rendererNode).injector;
|
|
1815
1942
|
}
|
|
1816
|
-
if (state[
|
|
1817
|
-
// we attach an arrow function to the Comment node
|
|
1943
|
+
if (state[NgtRendererClassId.type] === 'comment') {
|
|
1944
|
+
// NOTE: we attach an arrow function to the Comment node
|
|
1818
1945
|
// In our directives, we can call this function to then start tracking the RendererNode
|
|
1819
1946
|
// this is done to limit the amount of Nodes we need to process for getCreationState
|
|
1820
1947
|
rendererNode[SPECIAL_INTERNAL_ADD_COMMENT] = (node) => {
|
|
1821
|
-
if (node && node.__ngt_renderer__[
|
|
1948
|
+
if (node && node.__ngt_renderer__[NgtRendererClassId.type] === 'portal') {
|
|
1822
1949
|
this.portals.push(node);
|
|
1823
1950
|
}
|
|
1824
1951
|
else {
|
|
1825
|
-
this
|
|
1952
|
+
this.comments.push(rendererNode);
|
|
1826
1953
|
}
|
|
1827
1954
|
};
|
|
1828
1955
|
return rendererNode;
|
|
1829
1956
|
}
|
|
1830
|
-
if (state[
|
|
1831
|
-
state[
|
|
1832
|
-
state[
|
|
1833
|
-
state[
|
|
1957
|
+
if (state[NgtRendererClassId.type] === 'compound') {
|
|
1958
|
+
state[NgtRendererClassId.queueOps] = new Set();
|
|
1959
|
+
state[NgtRendererClassId.attributes] = {};
|
|
1960
|
+
state[NgtRendererClassId.properties] = {};
|
|
1834
1961
|
return rendererNode;
|
|
1835
1962
|
}
|
|
1836
1963
|
return rendererNode;
|
|
1837
1964
|
}
|
|
1838
1965
|
setParent(node, parent) {
|
|
1839
|
-
if (!node.__ngt_renderer__[
|
|
1840
|
-
node.__ngt_renderer__[
|
|
1966
|
+
if (!node.__ngt_renderer__[NgtRendererClassId.parent]) {
|
|
1967
|
+
node.__ngt_renderer__[NgtRendererClassId.parent] = parent;
|
|
1841
1968
|
}
|
|
1842
1969
|
}
|
|
1843
1970
|
addChild(node, child) {
|
|
1844
|
-
if (!node.__ngt_renderer__[
|
|
1845
|
-
node.__ngt_renderer__[
|
|
1971
|
+
if (!node.__ngt_renderer__[NgtRendererClassId.children].includes(child)) {
|
|
1972
|
+
node.__ngt_renderer__[NgtRendererClassId.children].push(child);
|
|
1846
1973
|
}
|
|
1847
1974
|
}
|
|
1848
1975
|
removeChild(node, child) {
|
|
1849
|
-
const index = node.__ngt_renderer__[
|
|
1976
|
+
const index = node.__ngt_renderer__?.[NgtRendererClassId.children].findIndex((c) => child === c);
|
|
1850
1977
|
if (index >= 0) {
|
|
1851
|
-
node.__ngt_renderer__[
|
|
1978
|
+
node.__ngt_renderer__[NgtRendererClassId.children].splice(index, 1);
|
|
1852
1979
|
}
|
|
1853
1980
|
}
|
|
1854
1981
|
setCompound(compound, instance) {
|
|
1982
|
+
const instanceRS = instance.__ngt_renderer__;
|
|
1983
|
+
if (instanceRS && instanceRS[NgtRendererClassId.parent]) {
|
|
1984
|
+
const parentRS = instanceRS[NgtRendererClassId.parent].__ngt_renderer__;
|
|
1985
|
+
// NOTE: if instance is already compounded by its parent. skip
|
|
1986
|
+
if (parentRS[NgtRendererClassId.type] === 'compound' &&
|
|
1987
|
+
parentRS[NgtRendererClassId.compounded] === instance) {
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1855
1991
|
const rS = compound.__ngt_renderer__;
|
|
1856
|
-
rS[
|
|
1857
|
-
const attributes = Object.keys(rS[
|
|
1858
|
-
const properties = Object.keys(rS[
|
|
1992
|
+
rS[NgtRendererClassId.compounded] = instance;
|
|
1993
|
+
const attributes = Object.keys(rS[NgtRendererClassId.attributes]);
|
|
1994
|
+
const properties = Object.keys(rS[NgtRendererClassId.properties]);
|
|
1859
1995
|
for (const key of attributes) {
|
|
1860
|
-
this.applyAttribute(instance, key, rS[
|
|
1996
|
+
this.applyAttribute(instance, key, rS[NgtRendererClassId.attributes][key]);
|
|
1861
1997
|
}
|
|
1862
1998
|
for (const key of properties) {
|
|
1863
|
-
this.applyProperty(instance, key, rS[
|
|
1999
|
+
this.applyProperty(instance, key, rS[NgtRendererClassId.properties][key]);
|
|
1864
2000
|
}
|
|
1865
2001
|
this.executeOperation(compound);
|
|
1866
2002
|
}
|
|
1867
2003
|
queueOperation(node, op) {
|
|
1868
|
-
node.__ngt_renderer__[
|
|
2004
|
+
node.__ngt_renderer__[NgtRendererClassId.queueOps].add(op);
|
|
1869
2005
|
}
|
|
1870
2006
|
executeOperation(node, type = 'op') {
|
|
1871
2007
|
const rS = node.__ngt_renderer__;
|
|
1872
|
-
if (rS[
|
|
1873
|
-
rS[
|
|
1874
|
-
if (op[
|
|
1875
|
-
op[
|
|
1876
|
-
rS[
|
|
2008
|
+
if (rS[NgtRendererClassId.queueOps]?.size) {
|
|
2009
|
+
rS[NgtRendererClassId.queueOps].forEach((op) => {
|
|
2010
|
+
if (op[NgtQueueOpClassId.type] === type) {
|
|
2011
|
+
op[NgtQueueOpClassId.op]();
|
|
2012
|
+
rS[NgtRendererClassId.queueOps].delete(op);
|
|
1877
2013
|
}
|
|
1878
2014
|
});
|
|
1879
2015
|
}
|
|
1880
2016
|
}
|
|
1881
2017
|
processPortalContainer(portal) {
|
|
1882
|
-
const injectorFactory = portal.__ngt_renderer__[
|
|
2018
|
+
const injectorFactory = portal.__ngt_renderer__[NgtRendererClassId.injectorFactory];
|
|
1883
2019
|
const injector = injectorFactory?.();
|
|
1884
2020
|
if (!injector)
|
|
1885
2021
|
return;
|
|
1886
|
-
const portalStore = injector.get(
|
|
2022
|
+
const portalStore = injector.get(NGT_STORE, null);
|
|
1887
2023
|
if (!portalStore)
|
|
1888
2024
|
return;
|
|
1889
2025
|
const portalContainer = portalStore.get('scene');
|
|
1890
2026
|
if (!portalContainer)
|
|
1891
2027
|
return;
|
|
1892
|
-
portal.__ngt_renderer__[
|
|
2028
|
+
portal.__ngt_renderer__[NgtRendererClassId.portalContainer] = this.createNode('three', portalContainer);
|
|
1893
2029
|
}
|
|
1894
2030
|
applyAttribute(node, name, value) {
|
|
1895
2031
|
const rS = node.__ngt_renderer__;
|
|
1896
|
-
if (rS[
|
|
2032
|
+
if (rS[NgtRendererClassId.destroyed])
|
|
1897
2033
|
return;
|
|
1898
2034
|
if (name === SPECIAL_PROPERTIES.RENDER_PRIORITY) {
|
|
1899
|
-
// priority needs to be set as an attribute string so that they can be set as early as possible
|
|
1900
|
-
// we convert that string to a number. if it's invalid, 0
|
|
2035
|
+
// NOTE: priority needs to be set as an attribute string so that they can be set as early as possible
|
|
2036
|
+
// we convert that string to a number. if it's invalid, default 0
|
|
1901
2037
|
let priority = Number(value);
|
|
1902
2038
|
if (isNaN(priority)) {
|
|
1903
2039
|
priority = 0;
|
|
@@ -1906,19 +2042,19 @@ class NgtRendererStore {
|
|
|
1906
2042
|
getLocalState(node).priority = priority;
|
|
1907
2043
|
}
|
|
1908
2044
|
if (name === SPECIAL_PROPERTIES.COMPOUND) {
|
|
1909
|
-
// we set the compound property on instance node now so we know that this instance is being compounded
|
|
1910
|
-
rS[
|
|
2045
|
+
// NOTE: we set the compound property on instance node now so we know that this instance is being compounded
|
|
2046
|
+
rS[NgtRendererClassId.compound] = [value === '' || value === 'first', {}];
|
|
1911
2047
|
return;
|
|
1912
2048
|
}
|
|
1913
2049
|
if (name === SPECIAL_PROPERTIES.ATTACH) {
|
|
1914
|
-
// handle attach as tring
|
|
2050
|
+
// NOTE: handle attach as tring
|
|
1915
2051
|
const paths = value.split('.');
|
|
1916
2052
|
if (paths.length)
|
|
1917
2053
|
getLocalState(node).attach = paths;
|
|
1918
2054
|
return;
|
|
1919
2055
|
}
|
|
1920
2056
|
if (name === SPECIAL_PROPERTIES.VALUE) {
|
|
1921
|
-
// coercion
|
|
2057
|
+
// NOTE: coercion
|
|
1922
2058
|
let maybeCoerced = value;
|
|
1923
2059
|
if (maybeCoerced === '' || maybeCoerced === 'true' || maybeCoerced === 'false') {
|
|
1924
2060
|
maybeCoerced = maybeCoerced === 'true' || maybeCoerced === '';
|
|
@@ -1926,25 +2062,26 @@ class NgtRendererStore {
|
|
|
1926
2062
|
else if (!isNaN(Number(maybeCoerced))) {
|
|
1927
2063
|
maybeCoerced = Number(maybeCoerced);
|
|
1928
2064
|
}
|
|
1929
|
-
rS[
|
|
2065
|
+
rS[NgtRendererClassId.rawValue] = maybeCoerced;
|
|
1930
2066
|
return;
|
|
1931
2067
|
}
|
|
1932
2068
|
applyProps(node, { [name]: value });
|
|
2069
|
+
this.updateNativeProps(node, name, value);
|
|
1933
2070
|
}
|
|
1934
2071
|
applyProperty(node, name, value) {
|
|
1935
2072
|
const rS = node.__ngt_renderer__;
|
|
1936
|
-
if (rS[
|
|
2073
|
+
if (rS[NgtRendererClassId.destroyed])
|
|
1937
2074
|
return;
|
|
1938
2075
|
// [ref]
|
|
1939
2076
|
if (name === SPECIAL_PROPERTIES.REF && is.ref(value)) {
|
|
1940
|
-
rS[
|
|
2077
|
+
rS[NgtRendererClassId.ref] = value;
|
|
1941
2078
|
value.nativeElement = node;
|
|
1942
2079
|
return;
|
|
1943
2080
|
}
|
|
1944
|
-
const parent = getLocalState(node).parent() || rS[
|
|
2081
|
+
const parent = getLocalState(node).parent() || rS[NgtRendererClassId.parent];
|
|
1945
2082
|
// [rawValue]
|
|
1946
2083
|
if (getLocalState(node).isRaw && name === SPECIAL_PROPERTIES.VALUE) {
|
|
1947
|
-
rS[
|
|
2084
|
+
rS[NgtRendererClassId.rawValue] = value;
|
|
1948
2085
|
if (parent)
|
|
1949
2086
|
attachThreeChild(parent, node);
|
|
1950
2087
|
return;
|
|
@@ -1956,13 +2093,14 @@ class NgtRendererStore {
|
|
|
1956
2093
|
attachThreeChild(parent, node);
|
|
1957
2094
|
return;
|
|
1958
2095
|
}
|
|
1959
|
-
const compound = rS[
|
|
1960
|
-
if (compound?.[
|
|
1961
|
-
name in compound[
|
|
1962
|
-
!compound[
|
|
1963
|
-
value = compound[
|
|
2096
|
+
const compound = rS[NgtRendererClassId.compound];
|
|
2097
|
+
if (compound?.[NgtCompoundClassId.props] &&
|
|
2098
|
+
name in compound[NgtCompoundClassId.props] &&
|
|
2099
|
+
!compound[NgtCompoundClassId.applyFirst]) {
|
|
2100
|
+
value = compound[NgtCompoundClassId.props][name];
|
|
1964
2101
|
}
|
|
1965
2102
|
applyProps(node, { [name]: value });
|
|
2103
|
+
this.updateNativeProps(node, name, value);
|
|
1966
2104
|
}
|
|
1967
2105
|
isCompound(name) {
|
|
1968
2106
|
return this.root.compoundPrefixes.some((prefix) => name.startsWith(prefix));
|
|
@@ -1970,7 +2108,7 @@ class NgtRendererStore {
|
|
|
1970
2108
|
isDOM(node) {
|
|
1971
2109
|
const rS = node['__ngt_renderer__'];
|
|
1972
2110
|
return (!rS ||
|
|
1973
|
-
(rS[
|
|
2111
|
+
(rS[NgtRendererClassId.type] !== 'compound' &&
|
|
1974
2112
|
(node instanceof Element || node instanceof Document || node instanceof Window)));
|
|
1975
2113
|
}
|
|
1976
2114
|
get rootScene() {
|
|
@@ -1980,37 +2118,37 @@ class NgtRendererStore {
|
|
|
1980
2118
|
return this.root.portals;
|
|
1981
2119
|
}
|
|
1982
2120
|
getClosestParentWithInstance(node) {
|
|
1983
|
-
let parent = node.__ngt_renderer__[
|
|
1984
|
-
while (parent && parent.__ngt_renderer__[
|
|
1985
|
-
parent = parent.__ngt_renderer__[
|
|
1986
|
-
? parent.__ngt_renderer__[
|
|
1987
|
-
: parent.__ngt_renderer__[
|
|
2121
|
+
let parent = node.__ngt_renderer__[NgtRendererClassId.parent];
|
|
2122
|
+
while (parent && parent.__ngt_renderer__[NgtRendererClassId.type] !== 'three') {
|
|
2123
|
+
parent = parent.__ngt_renderer__[NgtRendererClassId.portalContainer]
|
|
2124
|
+
? parent.__ngt_renderer__[NgtRendererClassId.portalContainer]
|
|
2125
|
+
: parent.__ngt_renderer__[NgtRendererClassId.parent];
|
|
1988
2126
|
}
|
|
1989
2127
|
return parent;
|
|
1990
2128
|
}
|
|
1991
2129
|
getClosestParentWithCompound(node) {
|
|
1992
|
-
if (node.__ngt_renderer__[
|
|
1993
|
-
return node.__ngt_renderer__[
|
|
2130
|
+
if (node.__ngt_renderer__[NgtRendererClassId.compoundParent]) {
|
|
2131
|
+
return node.__ngt_renderer__[NgtRendererClassId.compoundParent];
|
|
1994
2132
|
}
|
|
1995
|
-
let parent = node.__ngt_renderer__[
|
|
2133
|
+
let parent = node.__ngt_renderer__[NgtRendererClassId.parent];
|
|
1996
2134
|
if (parent &&
|
|
1997
|
-
parent.__ngt_renderer__[
|
|
1998
|
-
!parent.__ngt_renderer__[
|
|
2135
|
+
parent.__ngt_renderer__[NgtRendererClassId.type] === 'compound' &&
|
|
2136
|
+
!parent.__ngt_renderer__[NgtRendererClassId.compounded]) {
|
|
1999
2137
|
return parent;
|
|
2000
2138
|
}
|
|
2001
2139
|
while (parent &&
|
|
2002
|
-
(parent.__ngt_renderer__[
|
|
2003
|
-
!parent.__ngt_renderer__[
|
|
2004
|
-
parent.__ngt_renderer__[
|
|
2005
|
-
parent = parent.__ngt_renderer__[
|
|
2140
|
+
(parent.__ngt_renderer__[NgtRendererClassId.type] === 'three' ||
|
|
2141
|
+
!parent.__ngt_renderer__[NgtRendererClassId.compoundParent] ||
|
|
2142
|
+
parent.__ngt_renderer__[NgtRendererClassId.type] !== 'compound')) {
|
|
2143
|
+
parent = parent.__ngt_renderer__[NgtRendererClassId.parent];
|
|
2006
2144
|
}
|
|
2007
2145
|
if (!parent)
|
|
2008
2146
|
return;
|
|
2009
|
-
if (parent.__ngt_renderer__[
|
|
2010
|
-
parent.__ngt_renderer__[
|
|
2011
|
-
return parent.__ngt_renderer__[
|
|
2147
|
+
if (parent.__ngt_renderer__[NgtRendererClassId.type] === 'three' &&
|
|
2148
|
+
parent.__ngt_renderer__[NgtRendererClassId.compoundParent]) {
|
|
2149
|
+
return parent.__ngt_renderer__[NgtRendererClassId.compoundParent];
|
|
2012
2150
|
}
|
|
2013
|
-
if (!parent.__ngt_renderer__[
|
|
2151
|
+
if (!parent.__ngt_renderer__[NgtRendererClassId.compounded]) {
|
|
2014
2152
|
return parent;
|
|
2015
2153
|
}
|
|
2016
2154
|
return null;
|
|
@@ -2023,11 +2161,11 @@ class NgtRendererStore {
|
|
|
2023
2161
|
}
|
|
2024
2162
|
destroy(node, parent) {
|
|
2025
2163
|
const rS = node.__ngt_renderer__;
|
|
2026
|
-
if (rS
|
|
2164
|
+
if (!rS || rS[NgtRendererClassId.destroyed])
|
|
2027
2165
|
return;
|
|
2028
|
-
if (rS[
|
|
2029
|
-
rS[
|
|
2030
|
-
rS[
|
|
2166
|
+
if (rS[NgtRendererClassId.type] === 'three') {
|
|
2167
|
+
rS[NgtRendererClassId.compound] = undefined;
|
|
2168
|
+
rS[NgtRendererClassId.compoundParent] = undefined;
|
|
2031
2169
|
const localState = getLocalState(node);
|
|
2032
2170
|
if (localState.objects) {
|
|
2033
2171
|
untracked(localState.objects).forEach((obj) => this.destroy(obj, parent));
|
|
@@ -2052,58 +2190,73 @@ class NgtRendererStore {
|
|
|
2052
2190
|
delete node['__ngt__'];
|
|
2053
2191
|
}
|
|
2054
2192
|
}
|
|
2055
|
-
if (rS[
|
|
2056
|
-
rS[
|
|
2193
|
+
if (rS[NgtRendererClassId.type] === 'comment') {
|
|
2194
|
+
rS[NgtRendererClassId.injectorFactory] = null;
|
|
2057
2195
|
delete node[SPECIAL_INTERNAL_ADD_COMMENT];
|
|
2058
|
-
const index = this
|
|
2196
|
+
const index = this.comments.findIndex((comment) => comment === node);
|
|
2059
2197
|
if (index > -1) {
|
|
2060
|
-
this
|
|
2198
|
+
this.comments.splice(index, 1);
|
|
2061
2199
|
}
|
|
2062
2200
|
}
|
|
2063
|
-
if (rS[
|
|
2064
|
-
rS[
|
|
2201
|
+
if (rS[NgtRendererClassId.type] === 'portal') {
|
|
2202
|
+
rS[NgtRendererClassId.injectorFactory] = null;
|
|
2065
2203
|
const index = this.portals.findIndex((portal) => portal === node);
|
|
2066
2204
|
if (index > -1) {
|
|
2067
2205
|
this.portals.splice(index, 1);
|
|
2068
2206
|
}
|
|
2069
2207
|
}
|
|
2070
|
-
if (rS[
|
|
2071
|
-
rS[
|
|
2072
|
-
rS[
|
|
2073
|
-
rS[
|
|
2208
|
+
if (rS[NgtRendererClassId.type] === 'compound') {
|
|
2209
|
+
rS[NgtRendererClassId.compounded] = undefined;
|
|
2210
|
+
rS[NgtRendererClassId.attributes] = null;
|
|
2211
|
+
rS[NgtRendererClassId.properties] = null;
|
|
2074
2212
|
this.executeOperation(node, 'cleanUp');
|
|
2075
|
-
rS[
|
|
2076
|
-
rS[
|
|
2213
|
+
rS[NgtRendererClassId.queueOps].clear();
|
|
2214
|
+
rS[NgtRendererClassId.queueOps] = null;
|
|
2077
2215
|
}
|
|
2078
|
-
if (rS[
|
|
2216
|
+
if (rS[NgtRendererClassId.ref]) {
|
|
2079
2217
|
// nullify ref
|
|
2080
|
-
|
|
2081
|
-
|
|
2218
|
+
// but we do it later so that it doesn't hinder render
|
|
2219
|
+
// TODO: will this cause memory leak?
|
|
2220
|
+
requestAnimationFrame(() => {
|
|
2221
|
+
rS[NgtRendererClassId.ref].nativeElement = null;
|
|
2222
|
+
rS[NgtRendererClassId.ref] = undefined;
|
|
2223
|
+
});
|
|
2082
2224
|
}
|
|
2083
2225
|
// nullify parent
|
|
2084
|
-
rS[
|
|
2085
|
-
for (const renderChild of rS[
|
|
2086
|
-
if (renderChild.__ngt_renderer__[
|
|
2087
|
-
|
|
2226
|
+
rS[NgtRendererClassId.parent] = null;
|
|
2227
|
+
for (const renderChild of rS[NgtRendererClassId.children] || []) {
|
|
2228
|
+
if (renderChild.__ngt_renderer__?.[NgtRendererClassId.type] === 'three' && parent) {
|
|
2229
|
+
const closestInstance = this.getClosestParentWithInstance(parent);
|
|
2230
|
+
if (closestInstance) {
|
|
2231
|
+
removeThreeChild(closestInstance, renderChild, true);
|
|
2232
|
+
}
|
|
2088
2233
|
}
|
|
2089
2234
|
this.destroy(renderChild, parent);
|
|
2090
2235
|
}
|
|
2091
|
-
rS[
|
|
2092
|
-
rS[
|
|
2236
|
+
rS[NgtRendererClassId.children] = [];
|
|
2237
|
+
rS[NgtRendererClassId.destroyed] = true;
|
|
2093
2238
|
if (parent) {
|
|
2094
2239
|
this.removeChild(parent, node);
|
|
2095
2240
|
}
|
|
2096
2241
|
}
|
|
2242
|
+
updateNativeProps(node, key, value) {
|
|
2243
|
+
const localState = getLocalState(node);
|
|
2244
|
+
if (!localState || !localState.nativeProps)
|
|
2245
|
+
return;
|
|
2246
|
+
localState.nativeProps.set({ [key]: value });
|
|
2247
|
+
}
|
|
2097
2248
|
firstNonInjectedDirective(dir) {
|
|
2098
2249
|
let directive;
|
|
2099
|
-
|
|
2250
|
+
const destroyed = [];
|
|
2251
|
+
let i = this.comments.length - 1;
|
|
2100
2252
|
while (i >= 0) {
|
|
2101
|
-
const comment = this
|
|
2102
|
-
if (comment.__ngt_renderer__[
|
|
2253
|
+
const comment = this.comments[i];
|
|
2254
|
+
if (comment.__ngt_renderer__[NgtRendererClassId.destroyed]) {
|
|
2255
|
+
destroyed.push(i);
|
|
2103
2256
|
i--;
|
|
2104
2257
|
continue;
|
|
2105
2258
|
}
|
|
2106
|
-
const injector = comment.__ngt_renderer__[
|
|
2259
|
+
const injector = comment.__ngt_renderer__[NgtRendererClassId.injectorFactory]();
|
|
2107
2260
|
if (!injector) {
|
|
2108
2261
|
i--;
|
|
2109
2262
|
continue;
|
|
@@ -2115,73 +2268,85 @@ class NgtRendererStore {
|
|
|
2115
2268
|
}
|
|
2116
2269
|
i--;
|
|
2117
2270
|
}
|
|
2271
|
+
destroyed.forEach((index) => {
|
|
2272
|
+
this.comments.splice(index, 1);
|
|
2273
|
+
});
|
|
2118
2274
|
return directive;
|
|
2119
2275
|
}
|
|
2120
2276
|
tryGetPortalStore() {
|
|
2121
2277
|
let store;
|
|
2278
|
+
const destroyed = [];
|
|
2122
2279
|
// we only care about the portal states because NgtStore only differs per Portal
|
|
2123
2280
|
let i = this.portals.length - 1;
|
|
2124
2281
|
while (i >= 0) {
|
|
2125
2282
|
// loop through the portal state backwards to find the closest NgtStore
|
|
2126
2283
|
const portal = this.portals[i];
|
|
2127
|
-
if (portal.__ngt_renderer__[
|
|
2284
|
+
if (portal.__ngt_renderer__[NgtRendererClassId.destroyed]) {
|
|
2285
|
+
destroyed.push(i);
|
|
2128
2286
|
i--;
|
|
2129
2287
|
continue;
|
|
2130
2288
|
}
|
|
2131
|
-
const injector = portal.__ngt_renderer__[
|
|
2289
|
+
const injector = portal.__ngt_renderer__[NgtRendererClassId.injectorFactory]();
|
|
2132
2290
|
if (!injector) {
|
|
2133
2291
|
i--;
|
|
2134
2292
|
continue;
|
|
2135
2293
|
}
|
|
2136
|
-
const instance = injector.get(
|
|
2137
|
-
// only the instance with
|
|
2138
|
-
if (instance && instance.get('
|
|
2294
|
+
const instance = injector.get(NGT_STORE, null);
|
|
2295
|
+
// only the instance with previousRoot should pass
|
|
2296
|
+
if (instance && instance.get('previousRoot')) {
|
|
2139
2297
|
store = instance;
|
|
2140
2298
|
break;
|
|
2141
2299
|
}
|
|
2142
2300
|
i--;
|
|
2143
2301
|
}
|
|
2302
|
+
destroyed.forEach((index) => {
|
|
2303
|
+
this.portals.splice(index, 1);
|
|
2304
|
+
});
|
|
2144
2305
|
return store || this.root.store;
|
|
2145
2306
|
}
|
|
2146
2307
|
}
|
|
2147
2308
|
|
|
2148
2309
|
class NgtRendererFactory {
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2310
|
+
constructor() {
|
|
2311
|
+
this.delegateRendererFactory = inject(RendererFactory2, { skipSelf: true });
|
|
2312
|
+
this.zone = inject(NgZone);
|
|
2313
|
+
this.catalogue = injectNgtCatalogue();
|
|
2314
|
+
this.cdr = inject(ChangeDetectorRef);
|
|
2315
|
+
this.rendererMap = new Map();
|
|
2316
|
+
this.routedSet = new Set();
|
|
2317
|
+
// all Renderer instances share the same Store
|
|
2318
|
+
this.rendererStore = new NgtRendererStore({
|
|
2319
|
+
portals: [],
|
|
2320
|
+
store: injectNgtStore(),
|
|
2321
|
+
compoundPrefixes: inject(NGT_COMPOUND_PREFIXES),
|
|
2322
|
+
document: inject(DOCUMENT),
|
|
2323
|
+
});
|
|
2324
|
+
}
|
|
2162
2325
|
createRenderer(hostElement, type) {
|
|
2163
|
-
const
|
|
2326
|
+
const delegate = this.delegateRendererFactory.createRenderer(hostElement, type);
|
|
2164
2327
|
if (!type)
|
|
2165
|
-
return
|
|
2166
|
-
//
|
|
2167
|
-
|
|
2168
|
-
|
|
2328
|
+
return delegate;
|
|
2329
|
+
// TODO: handle html in canvas
|
|
2330
|
+
if (type['type'][HTML]) {
|
|
2331
|
+
this.rendererMap.set(type.id, delegate);
|
|
2332
|
+
return delegate;
|
|
2333
|
+
}
|
|
2169
2334
|
if (type['type'][ROUTED_SCENE]) {
|
|
2170
|
-
this
|
|
2335
|
+
this.routedSet.add(type.id);
|
|
2171
2336
|
}
|
|
2172
|
-
let renderer = this
|
|
2337
|
+
let renderer = this.rendererMap.get(type.id);
|
|
2173
2338
|
if (!renderer) {
|
|
2174
|
-
renderer = new NgtRenderer(
|
|
2339
|
+
renderer = new NgtRenderer(delegate, this.rendererStore, this.catalogue, this.zone, this.cdr,
|
|
2175
2340
|
// setting root scene if there's no routed scene OR this component is the routed Scene
|
|
2176
|
-
!hostElement && (this
|
|
2177
|
-
this
|
|
2341
|
+
!hostElement && (this.routedSet.size === 0 || this.routedSet.has(type.id)));
|
|
2342
|
+
this.rendererMap.set(type.id, renderer);
|
|
2178
2343
|
}
|
|
2179
2344
|
return renderer;
|
|
2180
2345
|
}
|
|
2181
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
2182
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.
|
|
2346
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtRendererFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2347
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtRendererFactory }); }
|
|
2183
2348
|
}
|
|
2184
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
2349
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtRendererFactory, decorators: [{
|
|
2185
2350
|
type: Injectable
|
|
2186
2351
|
}] });
|
|
2187
2352
|
/**
|
|
@@ -2213,7 +2378,7 @@ class NgtRenderer {
|
|
|
2213
2378
|
if (this.root) {
|
|
2214
2379
|
this.root = false;
|
|
2215
2380
|
const node = this.store.createNode('three', this.store.rootScene);
|
|
2216
|
-
node.__ngt_renderer__[
|
|
2381
|
+
node.__ngt_renderer__[NgtRendererClassId.injectorFactory] = () => getDebugNode(element).injector;
|
|
2217
2382
|
return node;
|
|
2218
2383
|
}
|
|
2219
2384
|
// handle compound
|
|
@@ -2226,7 +2391,10 @@ class NgtRenderer {
|
|
|
2226
2391
|
}
|
|
2227
2392
|
// handle raw value
|
|
2228
2393
|
if (name === SPECIAL_DOM_TAG.NGT_VALUE) {
|
|
2229
|
-
return this.store.createNode('three', Object.assign({ __ngt_renderer__: { rawValue: undefined } },
|
|
2394
|
+
return this.store.createNode('three', Object.assign({ __ngt_renderer__: { rawValue: undefined } },
|
|
2395
|
+
// NOTE: we assign this manually to a raw value node
|
|
2396
|
+
// because we say it is a 'three' node but we're not using prepare()
|
|
2397
|
+
{ __ngt__: { isRaw: true, parent: signal(null) } }));
|
|
2230
2398
|
}
|
|
2231
2399
|
const { injectedArgs, injectedParent, store } = this.store.getCreationState();
|
|
2232
2400
|
let parent = injectedParent;
|
|
@@ -2242,14 +2410,14 @@ class NgtRenderer {
|
|
|
2242
2410
|
const object = injectedArgs[0];
|
|
2243
2411
|
let localState = getLocalState(object);
|
|
2244
2412
|
if (!Object.keys(localState).length) {
|
|
2245
|
-
|
|
2246
|
-
localState = getLocalState(object);
|
|
2413
|
+
// NOTE: if an object isn't already "prepared", we prepare it
|
|
2414
|
+
localState = getLocalState(prepare(object, { store, args: injectedArgs, primitive: true }));
|
|
2247
2415
|
}
|
|
2248
2416
|
if (!localState.store)
|
|
2249
2417
|
localState.store = store;
|
|
2250
2418
|
const node = this.store.createNode('three', object);
|
|
2251
2419
|
if (parent) {
|
|
2252
|
-
node.__ngt_renderer__[
|
|
2420
|
+
node.__ngt_renderer__[NgtRendererClassId.injectedParent] = parent;
|
|
2253
2421
|
}
|
|
2254
2422
|
return node;
|
|
2255
2423
|
}
|
|
@@ -2269,7 +2437,7 @@ class NgtRenderer {
|
|
|
2269
2437
|
localState.attach = ['material'];
|
|
2270
2438
|
}
|
|
2271
2439
|
if (parent) {
|
|
2272
|
-
node.__ngt_renderer__[
|
|
2440
|
+
node.__ngt_renderer__[NgtRendererClassId.injectedParent] = parent;
|
|
2273
2441
|
}
|
|
2274
2442
|
return node;
|
|
2275
2443
|
}
|
|
@@ -2279,24 +2447,36 @@ class NgtRenderer {
|
|
|
2279
2447
|
return this.store.createNode('comment', this.delegate.createComment(value));
|
|
2280
2448
|
}
|
|
2281
2449
|
appendChild(parent, newChild) {
|
|
2282
|
-
// TODO: just ignore text node for now
|
|
2283
|
-
if (newChild instanceof Text)
|
|
2284
|
-
return;
|
|
2285
|
-
const cRS = newChild.__ngt_renderer__;
|
|
2286
2450
|
const pRS = parent.__ngt_renderer__;
|
|
2287
|
-
|
|
2451
|
+
const cRS = newChild.__ngt_renderer__;
|
|
2452
|
+
if (pRS[NgtRendererClassId.type] === 'dom' &&
|
|
2453
|
+
(newChild instanceof Text || cRS[NgtRendererClassId.type] === 'dom')) {
|
|
2454
|
+
this.store.addChild(parent, newChild);
|
|
2455
|
+
this.delegate.appendChild(parent, newChild);
|
|
2456
|
+
if (cRS) {
|
|
2457
|
+
this.store.setParent(newChild, parent);
|
|
2458
|
+
if (this.shouldFindGrandparentInstance(pRS, cRS, newChild)) {
|
|
2459
|
+
// we'll try to get the grandparent instance here so that we can run appendChild with both instances
|
|
2460
|
+
const closestGrandparentInstance = this.store.getClosestParentWithInstance(parent);
|
|
2461
|
+
if (closestGrandparentInstance)
|
|
2462
|
+
this.appendChild(closestGrandparentInstance, newChild);
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
return;
|
|
2466
|
+
}
|
|
2467
|
+
if (cRS?.[NgtRendererClassId.type] === 'comment') {
|
|
2288
2468
|
this.store.setParent(newChild, parent);
|
|
2289
2469
|
return;
|
|
2290
2470
|
}
|
|
2291
|
-
if (cRS[
|
|
2292
|
-
if (is.ref(cRS[
|
|
2293
|
-
const injector = cRS[
|
|
2471
|
+
if (cRS?.[NgtRendererClassId.injectedParent]) {
|
|
2472
|
+
if (is.ref(cRS[NgtRendererClassId.injectedParent])) {
|
|
2473
|
+
const injector = cRS[NgtRendererClassId.injectorFactory]().get(Injector, null);
|
|
2294
2474
|
if (!injector) {
|
|
2295
2475
|
console.warn(`[NGT] NgtRenderer is attempting to start an effect for injectedParent but no Injector is found.`);
|
|
2296
2476
|
return;
|
|
2297
2477
|
}
|
|
2298
2478
|
const watcher = effect(() => {
|
|
2299
|
-
const injectedParent = cRS[
|
|
2479
|
+
const injectedParent = cRS[NgtRendererClassId.injectedParent].nativeElement;
|
|
2300
2480
|
if (injectedParent && injectedParent !== parent) {
|
|
2301
2481
|
this.appendChild(injectedParent, newChild);
|
|
2302
2482
|
// only run this effect once
|
|
@@ -2306,38 +2486,38 @@ class NgtRenderer {
|
|
|
2306
2486
|
}, { injector, manualCleanup: true });
|
|
2307
2487
|
return;
|
|
2308
2488
|
}
|
|
2309
|
-
else if (parent !== cRS[
|
|
2310
|
-
this.appendChild(cRS[
|
|
2489
|
+
else if (parent !== cRS[NgtRendererClassId.injectedParent]) {
|
|
2490
|
+
this.appendChild(cRS[NgtRendererClassId.injectedParent], newChild);
|
|
2311
2491
|
return;
|
|
2312
2492
|
}
|
|
2313
2493
|
}
|
|
2314
2494
|
this.store.setParent(newChild, parent);
|
|
2315
2495
|
this.store.addChild(parent, newChild);
|
|
2316
2496
|
// if new child is a portal
|
|
2317
|
-
if (cRS[
|
|
2497
|
+
if (cRS?.[NgtRendererClassId.type] === 'portal') {
|
|
2318
2498
|
this.store.processPortalContainer(newChild);
|
|
2319
|
-
if (cRS[
|
|
2320
|
-
this.appendChild(parent, cRS[
|
|
2499
|
+
if (cRS[NgtRendererClassId.portalContainer]) {
|
|
2500
|
+
this.appendChild(parent, cRS[NgtRendererClassId.portalContainer]);
|
|
2321
2501
|
}
|
|
2322
2502
|
return;
|
|
2323
2503
|
}
|
|
2324
2504
|
// if parent is a portal
|
|
2325
|
-
if (pRS[
|
|
2505
|
+
if (pRS[NgtRendererClassId.type] === 'portal') {
|
|
2326
2506
|
this.store.processPortalContainer(parent);
|
|
2327
|
-
if (pRS[
|
|
2328
|
-
this.appendChild(pRS[
|
|
2507
|
+
if (pRS[NgtRendererClassId.portalContainer]) {
|
|
2508
|
+
this.appendChild(pRS[NgtRendererClassId.portalContainer], newChild);
|
|
2329
2509
|
}
|
|
2330
2510
|
return;
|
|
2331
2511
|
}
|
|
2332
2512
|
// if both are three instances, straightforward case
|
|
2333
|
-
if (pRS[
|
|
2513
|
+
if (pRS[NgtRendererClassId.type] === 'three' && cRS?.[NgtRendererClassId.type] === 'three') {
|
|
2334
2514
|
// if child already attached to a parent, skip
|
|
2335
2515
|
if (getLocalState(newChild).parent && untracked(getLocalState(newChild).parent))
|
|
2336
2516
|
return;
|
|
2337
2517
|
// attach THREE child
|
|
2338
2518
|
attachThreeChild(parent, newChild);
|
|
2339
2519
|
// here, we handle the special case of if the parent has a compoundParent, which means this child is part of a compound parent template
|
|
2340
|
-
if (!cRS[
|
|
2520
|
+
if (!cRS[NgtRendererClassId.compound])
|
|
2341
2521
|
return;
|
|
2342
2522
|
const closestGrandparentWithCompound = this.store.getClosestParentWithCompound(parent);
|
|
2343
2523
|
if (!closestGrandparentWithCompound)
|
|
@@ -2346,51 +2526,39 @@ class NgtRenderer {
|
|
|
2346
2526
|
return;
|
|
2347
2527
|
}
|
|
2348
2528
|
// if only the parent is the THREE instance
|
|
2349
|
-
if (pRS[
|
|
2350
|
-
for (const renderChild of cRS[
|
|
2529
|
+
if (pRS[NgtRendererClassId.type] === 'three') {
|
|
2530
|
+
for (const renderChild of cRS?.[NgtRendererClassId.children]) {
|
|
2351
2531
|
this.appendChild(parent, renderChild);
|
|
2352
2532
|
}
|
|
2353
2533
|
}
|
|
2354
2534
|
// if parent is a compound
|
|
2355
|
-
if (pRS[
|
|
2535
|
+
if (pRS[NgtRendererClassId.type] === 'compound') {
|
|
2356
2536
|
// if compound doesn't have a THREE instance set yet
|
|
2357
|
-
if (!pRS[
|
|
2537
|
+
if (!pRS[NgtRendererClassId.compounded] && cRS[NgtRendererClassId.type] === 'three') {
|
|
2358
2538
|
// if child is indeed an ngtCompound
|
|
2359
|
-
if (cRS[
|
|
2539
|
+
if (cRS[NgtRendererClassId.compound])
|
|
2360
2540
|
this.store.setCompound(parent, newChild);
|
|
2361
2541
|
// if not, we track the parent (that is supposedly the compound component) on this three instance
|
|
2362
|
-
else if (!cRS[
|
|
2363
|
-
cRS[
|
|
2542
|
+
else if (!cRS[NgtRendererClassId.compoundParent])
|
|
2543
|
+
cRS[NgtRendererClassId.compoundParent] = parent;
|
|
2364
2544
|
}
|
|
2365
2545
|
// reset the compound if it's changed
|
|
2366
|
-
if (pRS[
|
|
2367
|
-
cRS[
|
|
2368
|
-
cRS[
|
|
2369
|
-
pRS[
|
|
2546
|
+
if (pRS[NgtRendererClassId.compounded] &&
|
|
2547
|
+
cRS[NgtRendererClassId.type] === 'three' &&
|
|
2548
|
+
cRS[NgtRendererClassId.compound] &&
|
|
2549
|
+
pRS[NgtRendererClassId.compounded] !== newChild) {
|
|
2370
2550
|
this.store.setCompound(parent, newChild);
|
|
2371
2551
|
}
|
|
2372
2552
|
}
|
|
2373
|
-
|
|
2374
|
-
// if child is three but haven't been attached to a parent yet
|
|
2375
|
-
(cRS[0 /* NgtRendererClassId.type */] === 'three' && !untracked(getLocalState(newChild).parent)) ||
|
|
2376
|
-
// or both parent and child are DOM elements
|
|
2377
|
-
// or they are compound AND haven't had a THREE instance yet
|
|
2378
|
-
((pRS[0 /* NgtRendererClassId.type */] === 'dom' ||
|
|
2379
|
-
(pRS[0 /* NgtRendererClassId.type */] === 'compound' && !pRS[7 /* NgtRendererClassId.compounded */])) &&
|
|
2380
|
-
(cRS[0 /* NgtRendererClassId.type */] === 'dom' ||
|
|
2381
|
-
(cRS[0 /* NgtRendererClassId.type */] === 'compound' && !cRS[7 /* NgtRendererClassId.compounded */])));
|
|
2382
|
-
if (shouldFindGrandparentInstance) {
|
|
2553
|
+
if (this.shouldFindGrandparentInstance(pRS, cRS, newChild)) {
|
|
2383
2554
|
// we'll try to get the grandparent instance here so that we can run appendChild with both instances
|
|
2384
2555
|
const closestGrandparentInstance = this.store.getClosestParentWithInstance(parent);
|
|
2385
2556
|
if (closestGrandparentInstance)
|
|
2386
2557
|
this.appendChild(closestGrandparentInstance, newChild);
|
|
2558
|
+
return;
|
|
2387
2559
|
}
|
|
2388
2560
|
}
|
|
2389
|
-
insertBefore(parent, newChild
|
|
2390
|
-
// TODO: we might need these?
|
|
2391
|
-
// refChild: NgtRendererNode
|
|
2392
|
-
// isMove?: boolean | undefined
|
|
2393
|
-
) {
|
|
2561
|
+
insertBefore(parent, newChild) {
|
|
2394
2562
|
if (parent == null || !parent.__ngt_renderer__ || parent === newChild)
|
|
2395
2563
|
return;
|
|
2396
2564
|
this.appendChild(parent, newChild);
|
|
@@ -2398,16 +2566,28 @@ class NgtRenderer {
|
|
|
2398
2566
|
removeChild(parent, oldChild, isHostElement) {
|
|
2399
2567
|
const pRS = parent.__ngt_renderer__;
|
|
2400
2568
|
const cRS = oldChild.__ngt_renderer__;
|
|
2401
|
-
if (
|
|
2569
|
+
if ((!cRS || !pRS) &&
|
|
2570
|
+
parent instanceof Element &&
|
|
2571
|
+
(oldChild instanceof Element || oldChild instanceof Text || oldChild instanceof Comment)) {
|
|
2572
|
+
this.delegate.removeChild(parent, oldChild);
|
|
2573
|
+
this.store.destroy(oldChild, parent);
|
|
2574
|
+
return;
|
|
2575
|
+
}
|
|
2576
|
+
if (cRS[NgtRendererClassId.type] === 'dom' && (!pRS || pRS[NgtRendererClassId.type] === 'dom')) {
|
|
2577
|
+
this.delegate.removeChild(parent, oldChild);
|
|
2578
|
+
this.store.destroy(oldChild, parent);
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2581
|
+
if (pRS[NgtRendererClassId.type] === 'three' && cRS[NgtRendererClassId.type] === 'three') {
|
|
2402
2582
|
removeThreeChild(parent, oldChild, true);
|
|
2403
2583
|
this.store.destroy(oldChild, parent);
|
|
2404
2584
|
return;
|
|
2405
2585
|
}
|
|
2406
|
-
if (pRS[
|
|
2407
|
-
this.removeChild(pRS[
|
|
2586
|
+
if (pRS[NgtRendererClassId.type] === 'compound' && pRS[NgtRendererClassId.parent]) {
|
|
2587
|
+
this.removeChild(pRS[NgtRendererClassId.parent], oldChild, isHostElement);
|
|
2408
2588
|
return;
|
|
2409
2589
|
}
|
|
2410
|
-
if (pRS[
|
|
2590
|
+
if (pRS[NgtRendererClassId.type] === 'three') {
|
|
2411
2591
|
this.store.destroy(oldChild, parent);
|
|
2412
2592
|
return;
|
|
2413
2593
|
}
|
|
@@ -2418,44 +2598,49 @@ class NgtRenderer {
|
|
|
2418
2598
|
}
|
|
2419
2599
|
parentNode(node) {
|
|
2420
2600
|
const rS = node.__ngt_renderer__;
|
|
2421
|
-
if (rS?.[
|
|
2422
|
-
return rS[
|
|
2601
|
+
if (rS?.[NgtRendererClassId.parent])
|
|
2602
|
+
return rS[NgtRendererClassId.parent];
|
|
2423
2603
|
return this.delegate.parentNode(node);
|
|
2424
2604
|
}
|
|
2425
2605
|
setAttribute(el, name, value, namespace) {
|
|
2426
2606
|
const rS = el.__ngt_renderer__;
|
|
2427
|
-
if (rS[
|
|
2607
|
+
if (rS[NgtRendererClassId.type] === 'compound') {
|
|
2428
2608
|
// we don't have the compound instance yet
|
|
2429
|
-
rS[
|
|
2430
|
-
if (!rS[
|
|
2609
|
+
rS[NgtRendererClassId.attributes][name] = value;
|
|
2610
|
+
if (!rS[NgtRendererClassId.compounded]) {
|
|
2431
2611
|
this.store.queueOperation(el, ['op', () => this.setAttribute(el, name, value, namespace)]);
|
|
2432
2612
|
return;
|
|
2433
2613
|
}
|
|
2434
|
-
this.setAttribute(rS[
|
|
2614
|
+
this.setAttribute(rS[NgtRendererClassId.compounded], name, value, namespace);
|
|
2435
2615
|
return;
|
|
2436
2616
|
}
|
|
2437
|
-
if (rS[
|
|
2617
|
+
if (rS[NgtRendererClassId.type] === 'three') {
|
|
2438
2618
|
this.store.applyAttribute(el, name, value);
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2621
|
+
return this.delegate.setAttribute(el, name, value);
|
|
2439
2622
|
}
|
|
2440
2623
|
setProperty(el, name, value) {
|
|
2624
|
+
// TODO: should we support ref value
|
|
2441
2625
|
const rS = el.__ngt_renderer__;
|
|
2442
|
-
if (rS[
|
|
2626
|
+
if (rS[NgtRendererClassId.type] === 'compound') {
|
|
2443
2627
|
// we don't have the compound instance yet
|
|
2444
|
-
rS[
|
|
2445
|
-
if (!rS[
|
|
2628
|
+
rS[NgtRendererClassId.properties][name] = value;
|
|
2629
|
+
if (!rS[NgtRendererClassId.compounded]) {
|
|
2446
2630
|
this.store.queueOperation(el, ['op', () => this.setProperty(el, name, value)]);
|
|
2447
2631
|
return;
|
|
2448
2632
|
}
|
|
2449
|
-
if (rS[
|
|
2450
|
-
Object.assign(rS[
|
|
2451
|
-
props: Object.assign(rS[7 /* NgtRendererClassId.compounded */].__ngt_renderer__[5 /* NgtRendererClassId.compound */], { [name]: value }),
|
|
2452
|
-
});
|
|
2633
|
+
if (rS[NgtRendererClassId.compounded].__ngt_renderer__[NgtRendererClassId.compound]) {
|
|
2634
|
+
Object.assign(rS[NgtRendererClassId.compounded].__ngt_renderer__[NgtRendererClassId.compound][NgtCompoundClassId.props], { [name]: value });
|
|
2453
2635
|
}
|
|
2454
|
-
this.setProperty(rS[
|
|
2636
|
+
this.setProperty(rS[NgtRendererClassId.compounded], name, value);
|
|
2455
2637
|
return;
|
|
2456
2638
|
}
|
|
2457
|
-
if (rS[
|
|
2639
|
+
if (rS[NgtRendererClassId.type] === 'three') {
|
|
2458
2640
|
this.store.applyProperty(el, name, value);
|
|
2641
|
+
return;
|
|
2642
|
+
}
|
|
2643
|
+
return this.delegate.setProperty(el, name, value);
|
|
2459
2644
|
}
|
|
2460
2645
|
listen(target, eventName, callback) {
|
|
2461
2646
|
const rS = target.__ngt_renderer__;
|
|
@@ -2464,15 +2649,15 @@ class NgtRenderer {
|
|
|
2464
2649
|
if (!rS || this.store.isDOM(target)) {
|
|
2465
2650
|
return this.delegate.listen(target, eventName, callback);
|
|
2466
2651
|
}
|
|
2467
|
-
if (rS[
|
|
2468
|
-
(rS[
|
|
2469
|
-
const instance = rS[
|
|
2652
|
+
if (rS[NgtRendererClassId.type] === 'three' ||
|
|
2653
|
+
(rS[NgtRendererClassId.type] === 'compound' && rS[NgtRendererClassId.compounded])) {
|
|
2654
|
+
const instance = rS[NgtRendererClassId.compounded] || target;
|
|
2470
2655
|
const priority = getLocalState(target).priority;
|
|
2471
|
-
const targetCdr = rS[
|
|
2472
|
-
rS[
|
|
2656
|
+
const targetCdr = rS[NgtRendererClassId.injectorFactory]?.().get(ChangeDetectorRef, null) ||
|
|
2657
|
+
rS[NgtRendererClassId.parent]?.__ngt_renderer__?.[NgtRendererClassId.injectorFactory]?.().get(ChangeDetectorRef, null);
|
|
2473
2658
|
return processThreeEvent(instance, priority || 0, eventName, callback, this.zone, this.cdr, targetCdr);
|
|
2474
2659
|
}
|
|
2475
|
-
if (rS[
|
|
2660
|
+
if (rS[NgtRendererClassId.type] === 'compound' && !rS[NgtRendererClassId.compounded]) {
|
|
2476
2661
|
this.store.queueOperation(target, [
|
|
2477
2662
|
'op',
|
|
2478
2663
|
() => this.store.queueOperation(target, ['cleanUp', this.listen(target, eventName, callback)]),
|
|
@@ -2493,171 +2678,165 @@ class NgtRenderer {
|
|
|
2493
2678
|
}
|
|
2494
2679
|
return () => { };
|
|
2495
2680
|
}
|
|
2681
|
+
shouldFindGrandparentInstance(pRS, cRS, child) {
|
|
2682
|
+
const pType = pRS[NgtRendererClassId.type];
|
|
2683
|
+
const cType = cRS[NgtRendererClassId.type];
|
|
2684
|
+
const isParentCompounded = pRS[NgtRendererClassId.compounded];
|
|
2685
|
+
const isChildCompounded = cRS[NgtRendererClassId.compounded];
|
|
2686
|
+
// if child is three but haven't been attached to a parent yet
|
|
2687
|
+
const isDanglingThreeChild = cType === 'three' && !untracked(getLocalState(child).parent);
|
|
2688
|
+
// or both parent and child are DOM elements
|
|
2689
|
+
// or they are compound AND haven't had a THREE instance yet
|
|
2690
|
+
const isParentStillDOM = pType === 'dom' || (pType === 'compound' && !isParentCompounded);
|
|
2691
|
+
const isChildStillDOM = cType === 'dom' || (cType === 'compound' && !isChildCompounded);
|
|
2692
|
+
// and the child is a compounded compound
|
|
2693
|
+
const isCompoundChildCompounded = cType === 'compound' && !!isChildCompounded;
|
|
2694
|
+
return (isDanglingThreeChild ||
|
|
2695
|
+
(isParentStillDOM && isChildStillDOM) ||
|
|
2696
|
+
(isParentStillDOM && isCompoundChildCompounded));
|
|
2697
|
+
}
|
|
2496
2698
|
get data() {
|
|
2497
2699
|
return this.delegate.data;
|
|
2498
2700
|
}
|
|
2499
2701
|
}
|
|
2500
|
-
|
|
2501
|
-
function provideNgtRenderer({ store, changeDetectorRef, compoundPrefixes = [] }) {
|
|
2702
|
+
function provideNgtRenderer(store, compoundPrefixes, cdr) {
|
|
2502
2703
|
if (!compoundPrefixes.includes('ngts'))
|
|
2503
2704
|
compoundPrefixes.push('ngts');
|
|
2504
2705
|
if (!compoundPrefixes.includes('ngtp'))
|
|
2505
2706
|
compoundPrefixes.push('ngtp');
|
|
2506
2707
|
return makeEnvironmentProviders([
|
|
2507
2708
|
{ provide: RendererFactory2, useClass: NgtRendererFactory },
|
|
2508
|
-
{ provide: NgtStore, useValue: store },
|
|
2509
|
-
{ provide: ChangeDetectorRef, useValue: changeDetectorRef },
|
|
2510
2709
|
{ provide: NGT_COMPOUND_PREFIXES, useValue: compoundPrefixes },
|
|
2710
|
+
{ provide: ChangeDetectorRef, useValue: cdr },
|
|
2711
|
+
provideNgtStore(store),
|
|
2511
2712
|
provideZoneChangeDetection({ runCoalescing: true, eventCoalescing: true }),
|
|
2512
2713
|
]);
|
|
2513
2714
|
}
|
|
2514
2715
|
|
|
2515
|
-
class NgtCanvas
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2716
|
+
class NgtCanvas {
|
|
2717
|
+
constructor() {
|
|
2718
|
+
this.store = injectNgtStore();
|
|
2719
|
+
this.initRoot = injectCanvasRootInitializer();
|
|
2720
|
+
this.host = inject(ElementRef);
|
|
2721
|
+
this.viewContainerRef = inject(ViewContainerRef);
|
|
2722
|
+
this.injector = inject(Injector);
|
|
2723
|
+
this.environmentInjector = inject(EnvironmentInjector);
|
|
2724
|
+
this.zone = inject(NgZone);
|
|
2725
|
+
this.destroyRef = inject(DestroyRef);
|
|
2726
|
+
this.cdr = inject(ChangeDetectorRef);
|
|
2727
|
+
this.inputs = signalStore({
|
|
2728
|
+
shadows: false,
|
|
2729
|
+
linear: false,
|
|
2730
|
+
flat: false,
|
|
2731
|
+
legacy: false,
|
|
2732
|
+
orthographic: false,
|
|
2733
|
+
frameloop: 'always',
|
|
2734
|
+
dpr: [1, 2],
|
|
2735
|
+
events: createPointerEvents,
|
|
2736
|
+
});
|
|
2737
|
+
this.sceneGraphInputs = {};
|
|
2738
|
+
this.compoundPrefixes = [];
|
|
2739
|
+
this.created = new EventEmitter();
|
|
2740
|
+
this.inputsEventSource = this.inputs.select('eventSource');
|
|
2741
|
+
this.hbPointerEvents = computed(() => (!!this.inputsEventSource() ? 'none' : 'auto'));
|
|
2742
|
+
}
|
|
2523
2743
|
set linear(linear) {
|
|
2524
|
-
this.set({ linear });
|
|
2744
|
+
this.inputs.set({ linear });
|
|
2525
2745
|
}
|
|
2526
2746
|
set legacy(legacy) {
|
|
2527
|
-
this.set({ legacy });
|
|
2747
|
+
this.inputs.set({ legacy });
|
|
2528
2748
|
}
|
|
2529
2749
|
set flat(flat) {
|
|
2530
|
-
this.set({ flat });
|
|
2750
|
+
this.inputs.set({ flat });
|
|
2531
2751
|
}
|
|
2532
2752
|
set orthographic(orthographic) {
|
|
2533
|
-
this.set({ orthographic });
|
|
2753
|
+
this.inputs.set({ orthographic });
|
|
2534
2754
|
}
|
|
2535
2755
|
set frameloop(frameloop) {
|
|
2536
|
-
this.set({ frameloop });
|
|
2756
|
+
this.inputs.set({ frameloop });
|
|
2537
2757
|
}
|
|
2538
2758
|
set dpr(dpr) {
|
|
2539
|
-
this.set({ dpr });
|
|
2759
|
+
this.inputs.set({ dpr });
|
|
2540
2760
|
}
|
|
2541
2761
|
set raycaster(raycaster) {
|
|
2542
|
-
this.set({ raycaster });
|
|
2762
|
+
this.inputs.set({ raycaster });
|
|
2543
2763
|
}
|
|
2544
2764
|
set shadows(shadows) {
|
|
2545
|
-
this.set({ shadows });
|
|
2765
|
+
this.inputs.set({ shadows });
|
|
2546
2766
|
}
|
|
2547
2767
|
set camera(camera) {
|
|
2548
|
-
this.set({ camera });
|
|
2768
|
+
this.inputs.set({ camera });
|
|
2549
2769
|
}
|
|
2550
2770
|
set scene(scene) {
|
|
2551
|
-
this.set({ scene });
|
|
2771
|
+
this.inputs.set({ scene });
|
|
2552
2772
|
}
|
|
2553
2773
|
set gl(gl) {
|
|
2554
|
-
this.set({ gl });
|
|
2774
|
+
this.inputs.set({ gl });
|
|
2555
2775
|
}
|
|
2556
2776
|
set eventSource(eventSource) {
|
|
2557
|
-
this.set({ eventSource });
|
|
2777
|
+
this.inputs.set({ eventSource });
|
|
2558
2778
|
}
|
|
2559
2779
|
set eventPrefix(eventPrefix) {
|
|
2560
|
-
this.set({ eventPrefix });
|
|
2780
|
+
this.inputs.set({ eventPrefix });
|
|
2561
2781
|
}
|
|
2562
2782
|
set lookAt(lookAt) {
|
|
2563
|
-
this.set({ lookAt });
|
|
2783
|
+
this.inputs.set({ lookAt });
|
|
2564
2784
|
}
|
|
2565
2785
|
set performance(performance) {
|
|
2566
|
-
this.set({ performance });
|
|
2567
|
-
}
|
|
2568
|
-
#glRef;
|
|
2569
|
-
#glEnvInjector;
|
|
2570
|
-
constructor() {
|
|
2571
|
-
super({
|
|
2572
|
-
shadows: false,
|
|
2573
|
-
linear: false,
|
|
2574
|
-
flat: false,
|
|
2575
|
-
legacy: false,
|
|
2576
|
-
orthographic: false,
|
|
2577
|
-
frameloop: 'always',
|
|
2578
|
-
dpr: [1, 2],
|
|
2579
|
-
events: createPointerEvents,
|
|
2580
|
-
});
|
|
2581
|
-
this.#envInjector = inject(EnvironmentInjector);
|
|
2582
|
-
this.#injector = inject(Injector);
|
|
2583
|
-
this.#host = inject(ElementRef);
|
|
2584
|
-
this.#zone = inject(NgZone);
|
|
2585
|
-
this.#cdr = inject(ChangeDetectorRef);
|
|
2586
|
-
this.#store = inject(NgtStore);
|
|
2587
|
-
this.#isReady = this.#store.select('ready');
|
|
2588
|
-
this.sceneGraphInputs = {};
|
|
2589
|
-
this.compoundPrefixes = [];
|
|
2590
|
-
this.created = new EventEmitter();
|
|
2591
|
-
this.pointerMissed = new EventEmitter();
|
|
2592
|
-
inject(DestroyRef).onDestroy(() => {
|
|
2593
|
-
if (this.#glRef)
|
|
2594
|
-
this.#glRef.destroy();
|
|
2595
|
-
if (this.#glEnvInjector)
|
|
2596
|
-
this.#glEnvInjector.destroy();
|
|
2597
|
-
injectNgtLoader.destroy();
|
|
2598
|
-
this.#store.destroy(this.glCanvas.nativeElement);
|
|
2599
|
-
});
|
|
2600
|
-
}
|
|
2601
|
-
get hbPointerEvents() {
|
|
2602
|
-
return this.select('eventSource')() !== this.#host.nativeElement ? 'none' : 'auto';
|
|
2786
|
+
this.inputs.set({ performance });
|
|
2603
2787
|
}
|
|
2604
2788
|
ngOnChanges(changes) {
|
|
2605
|
-
if (changes['sceneGraphInputs'] && !changes['sceneGraphInputs'].firstChange && this
|
|
2606
|
-
this
|
|
2789
|
+
if (changes['sceneGraphInputs'] && !changes['sceneGraphInputs'].firstChange && this.glRef) {
|
|
2790
|
+
this.setSceneGraphInputs();
|
|
2607
2791
|
}
|
|
2608
2792
|
}
|
|
2609
2793
|
ngOnInit() {
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
this
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
this
|
|
2628
|
-
|
|
2629
|
-
this
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
this.#resizeRef.destroy();
|
|
2639
|
-
}
|
|
2640
|
-
if (width > 0 && height > 0) {
|
|
2641
|
-
if (!this.#store.isInit)
|
|
2642
|
-
this.#store.init();
|
|
2643
|
-
const inputs = this.select();
|
|
2644
|
-
this.#resizeRef = this.#zone.run(() => effect(() => {
|
|
2645
|
-
const canvasInputs = inputs();
|
|
2646
|
-
this.#zone.runOutsideAngular(() => {
|
|
2647
|
-
this.#store.configure({ ...canvasInputs, size: { width, height, top, left } }, this.glCanvas.nativeElement);
|
|
2794
|
+
// NOTE: we resolve glCanvas at this point, setup the configurator
|
|
2795
|
+
this.configurator = this.initRoot(this.glCanvas.nativeElement);
|
|
2796
|
+
this.destroyRef.onDestroy(() => {
|
|
2797
|
+
this.glEnvironmentInjector?.destroy();
|
|
2798
|
+
this.glRef?.destroy();
|
|
2799
|
+
this.resizeEffectRef?.destroy();
|
|
2800
|
+
injectNgtLoader.destroy();
|
|
2801
|
+
this.configurator?.destroy();
|
|
2802
|
+
});
|
|
2803
|
+
}
|
|
2804
|
+
// NOTE: runs outside of Zone due to emitInZone: false
|
|
2805
|
+
onResize(result) {
|
|
2806
|
+
if (result.width > 0 && result.height > 0) {
|
|
2807
|
+
this.resizeEffectRef?.destroy();
|
|
2808
|
+
const inputs = this.inputs.select();
|
|
2809
|
+
// NOTE: go back into zone so that effect runs
|
|
2810
|
+
// TODO: Double-check when effect is made not depended on zone
|
|
2811
|
+
this.resizeEffectRef = this.zone.run(() => effect(() => {
|
|
2812
|
+
this.zone.runOutsideAngular(() => {
|
|
2813
|
+
if (!this.configurator)
|
|
2814
|
+
this.configurator = this.initRoot(this.glCanvas.nativeElement);
|
|
2815
|
+
this.configurator.configure({ ...inputs(), size: result });
|
|
2816
|
+
if (this.glRef) {
|
|
2817
|
+
this.cdr.detectChanges();
|
|
2818
|
+
}
|
|
2819
|
+
else {
|
|
2820
|
+
this.render();
|
|
2821
|
+
}
|
|
2648
2822
|
});
|
|
2649
|
-
}, {
|
|
2823
|
+
}, { manualCleanup: true, injector: this.injector }));
|
|
2650
2824
|
}
|
|
2651
2825
|
}
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
const
|
|
2826
|
+
render() {
|
|
2827
|
+
this.glEnvironmentInjector?.destroy();
|
|
2828
|
+
this.glRef?.destroy();
|
|
2829
|
+
// Flag the canvas active, rendering will now begin
|
|
2830
|
+
this.store.set((state) => ({ internal: { ...state.internal, active: true } }));
|
|
2831
|
+
const inputs = this.inputs.get();
|
|
2832
|
+
const state = this.store.get();
|
|
2658
2833
|
// connect to event source
|
|
2659
|
-
state.events.connect?.(
|
|
2660
|
-
|
|
2834
|
+
state.events.connect?.(inputs.eventSource
|
|
2835
|
+
? is.ref(inputs.eventSource)
|
|
2836
|
+
? inputs.eventSource.nativeElement
|
|
2837
|
+
: inputs.eventSource
|
|
2838
|
+
: this.host.nativeElement);
|
|
2839
|
+
// setup compute for eventPrefix
|
|
2661
2840
|
if (inputs.eventPrefix) {
|
|
2662
2841
|
state.setEvents({
|
|
2663
2842
|
compute: (event, store) => {
|
|
@@ -2671,70 +2850,65 @@ class NgtCanvas extends NgtSignalStore {
|
|
|
2671
2850
|
}
|
|
2672
2851
|
// emit created event if observed
|
|
2673
2852
|
if (this.created.observed) {
|
|
2674
|
-
// but go back into zone to
|
|
2675
|
-
this
|
|
2676
|
-
this.created.emit(this
|
|
2853
|
+
// but go back into zone to do so
|
|
2854
|
+
this.zone.run(() => {
|
|
2855
|
+
this.created.emit(this.store.get());
|
|
2677
2856
|
});
|
|
2678
2857
|
}
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
changeDetectorRef: this.#cdr,
|
|
2687
|
-
compoundPrefixes: this.compoundPrefixes,
|
|
2688
|
-
}),
|
|
2689
|
-
], this.#envInjector);
|
|
2690
|
-
this.#glRef = this.glAnchor.createComponent(this.sceneGraph, {
|
|
2691
|
-
environmentInjector: this.#glEnvInjector,
|
|
2692
|
-
});
|
|
2693
|
-
this.#setSceneGraphInputs();
|
|
2694
|
-
this.#overrideChangeDetectorRef();
|
|
2695
|
-
safeDetectChanges(this.#cdr);
|
|
2858
|
+
if (!this.store.get('events', 'connected')) {
|
|
2859
|
+
this.store.get('events').connect?.(this.glCanvas.nativeElement);
|
|
2860
|
+
}
|
|
2861
|
+
this.glEnvironmentInjector = createEnvironmentInjector([provideNgtRenderer(this.store, this.compoundPrefixes, this.cdr)], this.environmentInjector);
|
|
2862
|
+
this.glRef = this.viewContainerRef.createComponent(this.sceneGraph, {
|
|
2863
|
+
environmentInjector: this.glEnvironmentInjector,
|
|
2864
|
+
injector: this.injector,
|
|
2696
2865
|
});
|
|
2866
|
+
this.overrideChangeDetectorRef();
|
|
2867
|
+
this.setSceneGraphInputs();
|
|
2697
2868
|
}
|
|
2698
|
-
|
|
2699
|
-
const originalDetectChanges = this
|
|
2700
|
-
this
|
|
2869
|
+
overrideChangeDetectorRef() {
|
|
2870
|
+
const originalDetectChanges = this.cdr.detectChanges.bind(this.cdr);
|
|
2871
|
+
this.cdr.detectChanges = () => {
|
|
2701
2872
|
originalDetectChanges();
|
|
2702
|
-
safeDetectChanges(this
|
|
2873
|
+
safeDetectChanges(this.glRef?.changeDetectorRef);
|
|
2703
2874
|
};
|
|
2704
2875
|
}
|
|
2705
|
-
|
|
2706
|
-
this
|
|
2707
|
-
if (this
|
|
2876
|
+
setSceneGraphInputs() {
|
|
2877
|
+
this.zone.run(() => {
|
|
2878
|
+
if (this.glRef) {
|
|
2708
2879
|
for (const [key, value] of Object.entries(this.sceneGraphInputs)) {
|
|
2709
|
-
this
|
|
2880
|
+
this.glRef.setInput(key, value);
|
|
2710
2881
|
}
|
|
2711
|
-
|
|
2882
|
+
this.glRef.changeDetectorRef.detectChanges();
|
|
2712
2883
|
}
|
|
2713
2884
|
});
|
|
2714
2885
|
}
|
|
2715
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
2716
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2886
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtCanvas, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2887
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.2", 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: `
|
|
2888
|
+
<div (ngxResize)="onResize($event)" style="height: 100%; width: 100%;">
|
|
2889
|
+
<canvas #glCanvas style="display: block;"></canvas>
|
|
2890
|
+
</div>
|
|
2891
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgxResize, selector: "[ngxResize]", inputs: ["ngxResizeOptions"], outputs: ["ngxResize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2721
2892
|
}
|
|
2722
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
2893
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtCanvas, decorators: [{
|
|
2723
2894
|
type: Component,
|
|
2724
2895
|
args: [{
|
|
2725
2896
|
selector: 'ngt-canvas',
|
|
2726
2897
|
standalone: true,
|
|
2727
2898
|
template: `
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2899
|
+
<div (ngxResize)="onResize($event)" style="height: 100%; width: 100%;">
|
|
2900
|
+
<canvas #glCanvas style="display: block;"></canvas>
|
|
2901
|
+
</div>
|
|
2902
|
+
`,
|
|
2732
2903
|
imports: [NgxResize],
|
|
2733
|
-
providers: [
|
|
2734
|
-
host: {
|
|
2904
|
+
providers: [provideNgxResizeOptions({ emitInZone: false, emitInitialResult: true }), provideNgtStore()],
|
|
2905
|
+
host: {
|
|
2906
|
+
style: 'display: block;position: relative;width: 100%;height: 100%;overflow: hidden;',
|
|
2907
|
+
'[style.pointerEvents]': 'hbPointerEvents()',
|
|
2908
|
+
},
|
|
2735
2909
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2736
2910
|
}]
|
|
2737
|
-
}],
|
|
2911
|
+
}], propDecorators: { sceneGraph: [{
|
|
2738
2912
|
type: Input,
|
|
2739
2913
|
args: [{ required: true }]
|
|
2740
2914
|
}], sceneGraphInputs: [{
|
|
@@ -2773,34 +2947,58 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
|
|
|
2773
2947
|
type: Input
|
|
2774
2948
|
}], created: [{
|
|
2775
2949
|
type: Output
|
|
2776
|
-
}], pointerMissed: [{
|
|
2777
|
-
type: Output
|
|
2778
2950
|
}], glCanvas: [{
|
|
2779
2951
|
type: ViewChild,
|
|
2780
2952
|
args: ['glCanvas', { static: true }]
|
|
2781
|
-
}], glAnchor: [{
|
|
2782
|
-
type: ViewChild,
|
|
2783
|
-
args: ['glCanvas', { static: true, read: ViewContainerRef }]
|
|
2784
2953
|
}] } });
|
|
2785
2954
|
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2955
|
+
class NgtKey extends NgtCommonDirective {
|
|
2956
|
+
constructor() {
|
|
2957
|
+
super(...arguments);
|
|
2958
|
+
this.lastKey = '';
|
|
2959
|
+
}
|
|
2960
|
+
static { this.processComment = false; }
|
|
2961
|
+
validate() {
|
|
2962
|
+
return false;
|
|
2963
|
+
}
|
|
2964
|
+
set key(key) {
|
|
2965
|
+
const normalizedKey = JSON.stringify(key);
|
|
2966
|
+
if (this.lastKey !== normalizedKey) {
|
|
2967
|
+
this.lastKey = normalizedKey;
|
|
2968
|
+
this.createView();
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtKey, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2972
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.2", type: NgtKey, isStandalone: true, selector: "ng-template[key]", inputs: { key: "key" }, usesInheritance: true, ngImport: i0 }); }
|
|
2973
|
+
}
|
|
2974
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtKey, decorators: [{
|
|
2975
|
+
type: Directive,
|
|
2976
|
+
args: [{ selector: 'ng-template[key]', standalone: true }]
|
|
2977
|
+
}], propDecorators: { key: [{
|
|
2978
|
+
type: Input
|
|
2979
|
+
}] } });
|
|
2980
|
+
|
|
2981
|
+
class NgtRepeat extends NgForOf {
|
|
2982
|
+
set ngForRepeat(count) {
|
|
2983
|
+
this.ngForOf = Number.isInteger(count) ? Array.from({ length: count }, (_, i) => i) : [];
|
|
2984
|
+
}
|
|
2985
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtRepeat, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2986
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.2", type: NgtRepeat, isStandalone: true, selector: "[ngFor][ngForRepeat]", inputs: { ngForRepeat: "ngForRepeat" }, usesInheritance: true, ngImport: i0 }); }
|
|
2794
2987
|
}
|
|
2988
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtRepeat, decorators: [{
|
|
2989
|
+
type: Directive,
|
|
2990
|
+
args: [{ selector: '[ngFor][ngForRepeat]', standalone: true }]
|
|
2991
|
+
}], propDecorators: { ngForRepeat: [{
|
|
2992
|
+
type: Input
|
|
2993
|
+
}] } });
|
|
2795
2994
|
|
|
2796
2995
|
function injectNgtRef(initial = null, injector) {
|
|
2797
|
-
injector = assertInjectionContext(injectNgtRef
|
|
2996
|
+
injector = assertInjectionContext(injectNgtRef);
|
|
2997
|
+
const ref = is.ref(initial) ? initial : new ElementRef(initial);
|
|
2998
|
+
const signalRef = signal(ref.nativeElement);
|
|
2999
|
+
const readonlySignal = signalRef.asReadonly();
|
|
3000
|
+
const cached = new Map();
|
|
2798
3001
|
return runInInjectionContext(injector, () => {
|
|
2799
|
-
const cdr = inject(ChangeDetectorRef);
|
|
2800
|
-
const ref = is.ref(initial) ? initial : new ElementRef(initial);
|
|
2801
|
-
const signalRef = createSignal(ref.nativeElement);
|
|
2802
|
-
const readonlySignal = signalRef.asReadonly();
|
|
2803
|
-
const cached = new Map();
|
|
2804
3002
|
inject(DestroyRef).onDestroy(() => void cached.clear());
|
|
2805
3003
|
const children = (type = 'objects') => {
|
|
2806
3004
|
if (!cached.has(type)) {
|
|
@@ -2820,36 +3018,24 @@ function injectNgtRef(initial = null, injector) {
|
|
|
2820
3018
|
}
|
|
2821
3019
|
return cached.get(type);
|
|
2822
3020
|
};
|
|
2823
|
-
Object.
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
3021
|
+
Object.defineProperties(ref, {
|
|
3022
|
+
nativeElement: {
|
|
3023
|
+
set: (newElement) => {
|
|
3024
|
+
untracked(() => {
|
|
3025
|
+
if (newElement !== signalRef()) {
|
|
3026
|
+
signalRef.set(newElement);
|
|
3027
|
+
}
|
|
3028
|
+
});
|
|
3029
|
+
},
|
|
3030
|
+
get: readonlySignal,
|
|
2829
3031
|
},
|
|
2830
|
-
get: () => readonlySignal
|
|
3032
|
+
untracked: { get: () => untracked(readonlySignal) },
|
|
3033
|
+
children: { get: () => children },
|
|
2831
3034
|
});
|
|
2832
|
-
|
|
2833
|
-
get: () => untracked(readonlySignal),
|
|
2834
|
-
});
|
|
2835
|
-
return Object.assign(ref, { children });
|
|
3035
|
+
return ref;
|
|
2836
3036
|
});
|
|
2837
3037
|
}
|
|
2838
3038
|
|
|
2839
|
-
class NgtRepeat extends NgForOf {
|
|
2840
|
-
set ngForRepeat(count) {
|
|
2841
|
-
this.ngForOf = Number.isInteger(count) ? Array.from({ length: count }, (_, i) => i) : [];
|
|
2842
|
-
}
|
|
2843
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRepeat, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2844
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtRepeat, isStandalone: true, selector: "[ngFor][ngForRepeat]", inputs: { ngForRepeat: "ngForRepeat" }, usesInheritance: true, ngImport: i0 }); }
|
|
2845
|
-
}
|
|
2846
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRepeat, decorators: [{
|
|
2847
|
-
type: Directive,
|
|
2848
|
-
args: [{ selector: '[ngFor][ngForRepeat]', standalone: true }]
|
|
2849
|
-
}], propDecorators: { ngForRepeat: [{
|
|
2850
|
-
type: Input
|
|
2851
|
-
}] } });
|
|
2852
|
-
|
|
2853
3039
|
const privateKeys = [
|
|
2854
3040
|
'get',
|
|
2855
3041
|
'set',
|
|
@@ -2864,21 +3050,17 @@ const privateKeys = [
|
|
|
2864
3050
|
'viewport',
|
|
2865
3051
|
];
|
|
2866
3052
|
class NgtPortalBeforeRender {
|
|
2867
|
-
#portalStore;
|
|
2868
|
-
#subscription;
|
|
2869
3053
|
constructor() {
|
|
2870
|
-
this
|
|
3054
|
+
this.portalStore = injectNgtStore();
|
|
3055
|
+
this.injector = inject(Injector);
|
|
2871
3056
|
this.renderPriority = 1;
|
|
2872
3057
|
this.beforeRender = new EventEmitter();
|
|
2873
|
-
inject(DestroyRef).onDestroy(() => {
|
|
2874
|
-
this.#subscription?.();
|
|
2875
|
-
});
|
|
2876
3058
|
}
|
|
2877
3059
|
ngOnInit() {
|
|
2878
3060
|
let oldClear;
|
|
2879
|
-
|
|
2880
|
-
this.beforeRender.emit({ ...this
|
|
2881
|
-
const { gl, scene, camera } = this
|
|
3061
|
+
injectBeforeRender(({ delta, frame }) => {
|
|
3062
|
+
this.beforeRender.emit({ ...this.portalStore.get(), delta, frame });
|
|
3063
|
+
const { gl, scene, camera } = this.portalStore.get();
|
|
2882
3064
|
oldClear = gl.autoClear;
|
|
2883
3065
|
if (this.renderPriority === 1) {
|
|
2884
3066
|
// clear scene and render with default
|
|
@@ -2891,15 +3073,15 @@ class NgtPortalBeforeRender {
|
|
|
2891
3073
|
gl.render(scene, camera);
|
|
2892
3074
|
// restore
|
|
2893
3075
|
gl.autoClear = oldClear;
|
|
2894
|
-
}, this.renderPriority, this
|
|
3076
|
+
}, { priority: this.renderPriority, injector: this.injector });
|
|
2895
3077
|
}
|
|
2896
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
2897
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.
|
|
3078
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtPortalBeforeRender, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3079
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.2", type: NgtPortalBeforeRender, isStandalone: true, selector: "[ngtPortalBeforeRender]", inputs: { renderPriority: "renderPriority", parentScene: "parentScene", parentCamera: "parentCamera" }, outputs: { beforeRender: "beforeRender" }, ngImport: i0 }); }
|
|
2898
3080
|
}
|
|
2899
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
3081
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtPortalBeforeRender, decorators: [{
|
|
2900
3082
|
type: Directive,
|
|
2901
3083
|
args: [{ selector: '[ngtPortalBeforeRender]', standalone: true }]
|
|
2902
|
-
}],
|
|
3084
|
+
}], propDecorators: { renderPriority: [{
|
|
2903
3085
|
type: Input
|
|
2904
3086
|
}], parentScene: [{
|
|
2905
3087
|
type: Input,
|
|
@@ -2918,96 +3100,90 @@ class NgtPortalContent {
|
|
|
2918
3100
|
delete commentNode[SPECIAL_INTERNAL_ADD_COMMENT];
|
|
2919
3101
|
}
|
|
2920
3102
|
}
|
|
2921
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
2922
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.
|
|
3103
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtPortalContent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ViewContainerRef, skipSelf: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3104
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.2", type: NgtPortalContent, isStandalone: true, selector: "ng-template[ngtPortalContent]", ngImport: i0 }); }
|
|
2923
3105
|
}
|
|
2924
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
3106
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtPortalContent, decorators: [{
|
|
2925
3107
|
type: Directive,
|
|
2926
3108
|
args: [{ selector: 'ng-template[ngtPortalContent]', standalone: true }]
|
|
2927
3109
|
}], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ViewContainerRef, decorators: [{
|
|
2928
3110
|
type: SkipSelf
|
|
2929
3111
|
}] }]; } });
|
|
2930
|
-
class NgtPortal
|
|
3112
|
+
class NgtPortal {
|
|
2931
3113
|
set container(container) {
|
|
2932
|
-
this.set({ container });
|
|
2933
|
-
}
|
|
2934
|
-
set
|
|
2935
|
-
this.set({ state });
|
|
2936
|
-
}
|
|
2937
|
-
#parentStore;
|
|
2938
|
-
#portalStore;
|
|
2939
|
-
#injector;
|
|
2940
|
-
#zone;
|
|
2941
|
-
#raycaster;
|
|
2942
|
-
#pointer;
|
|
2943
|
-
#portalContentView;
|
|
3114
|
+
this.inputs.set({ container });
|
|
3115
|
+
}
|
|
3116
|
+
set portalState(state) {
|
|
3117
|
+
this.inputs.set({ state });
|
|
3118
|
+
}
|
|
2944
3119
|
constructor() {
|
|
2945
|
-
|
|
3120
|
+
this.inputs = signalStore({ container: injectNgtRef(prepare(new THREE.Scene())) });
|
|
2946
3121
|
this.autoRender = true;
|
|
2947
3122
|
this.autoRenderPriority = 1;
|
|
2948
3123
|
this.beforeRender = new EventEmitter();
|
|
2949
|
-
this
|
|
2950
|
-
this.parentScene = this
|
|
2951
|
-
this.parentCamera = this
|
|
2952
|
-
this
|
|
2953
|
-
this
|
|
2954
|
-
this
|
|
2955
|
-
this
|
|
2956
|
-
this
|
|
3124
|
+
this.parentStore = injectNgtStore({ skipSelf: true });
|
|
3125
|
+
this.parentScene = this.parentStore.get('scene');
|
|
3126
|
+
this.parentCamera = this.parentStore.get('camera');
|
|
3127
|
+
this.portalStore = injectNgtStore({ self: true });
|
|
3128
|
+
this.injector = inject(Injector);
|
|
3129
|
+
this.zone = inject(NgZone);
|
|
3130
|
+
this.raycaster = new THREE.Raycaster();
|
|
3131
|
+
this.pointer = new THREE.Vector2();
|
|
2957
3132
|
this.portalContentRendered = false;
|
|
2958
3133
|
inject(DestroyRef).onDestroy(() => {
|
|
2959
|
-
if (this
|
|
2960
|
-
this
|
|
3134
|
+
if (this.portalContentView && !this.portalContentView.destroyed) {
|
|
3135
|
+
this.portalContentView.destroy();
|
|
2961
3136
|
}
|
|
2962
3137
|
});
|
|
2963
3138
|
}
|
|
2964
3139
|
ngOnInit() {
|
|
2965
|
-
const previousState = this
|
|
2966
|
-
const inputsState = this.get();
|
|
3140
|
+
const previousState = this.parentStore.get();
|
|
3141
|
+
const inputsState = this.inputs.get();
|
|
2967
3142
|
if (!inputsState.state && this.autoRender) {
|
|
2968
3143
|
inputsState.state = { events: { priority: this.autoRenderPriority + 1 } };
|
|
2969
3144
|
}
|
|
2970
3145
|
const { events, size, ...restInputsState } = inputsState.state || {};
|
|
2971
3146
|
const containerState = inputsState.container;
|
|
2972
|
-
|
|
3147
|
+
let container = is.ref(containerState) ? containerState.nativeElement : containerState;
|
|
3148
|
+
if (!is.instance(container)) {
|
|
3149
|
+
container = prepare(container);
|
|
3150
|
+
}
|
|
2973
3151
|
const localState = getLocalState(container);
|
|
2974
3152
|
if (!localState.store) {
|
|
2975
|
-
localState.store = this
|
|
3153
|
+
localState.store = this.portalStore;
|
|
2976
3154
|
}
|
|
2977
|
-
this
|
|
3155
|
+
this.portalStore.set({
|
|
2978
3156
|
...previousState,
|
|
2979
3157
|
scene: container,
|
|
2980
|
-
raycaster: this
|
|
2981
|
-
pointer: this
|
|
2982
|
-
|
|
3158
|
+
raycaster: this.raycaster,
|
|
3159
|
+
pointer: this.pointer,
|
|
3160
|
+
previousRoot: this.parentStore,
|
|
2983
3161
|
events: { ...previousState.events, ...(events || {}) },
|
|
2984
3162
|
size: { ...previousState.size, ...(size || {}) },
|
|
2985
3163
|
...restInputsState,
|
|
2986
|
-
|
|
2987
|
-
set: this.#portalStore.set.bind(this.#portalStore),
|
|
2988
|
-
setEvents: (events) => this.#portalStore.set((state) => ({ ...state, events: { ...state.events, ...events } })),
|
|
3164
|
+
setEvents: (events) => this.portalStore.set((state) => ({ ...state, events: { ...state.events, ...events } })),
|
|
2989
3165
|
});
|
|
2990
|
-
const parentState = this
|
|
3166
|
+
const parentState = this.parentStore.select();
|
|
2991
3167
|
effect(() => {
|
|
2992
3168
|
const previous = parentState();
|
|
2993
|
-
this
|
|
2994
|
-
this
|
|
3169
|
+
this.zone.runOutsideAngular(() => {
|
|
3170
|
+
this.portalStore.set((state) => this.inject(previous, state));
|
|
2995
3171
|
});
|
|
2996
|
-
}, { injector: this
|
|
3172
|
+
}, { injector: this.injector });
|
|
2997
3173
|
requestAnimationFrame(() => {
|
|
2998
|
-
this
|
|
3174
|
+
this.portalStore.set((injectState) => this.inject(this.parentStore.get(), injectState));
|
|
2999
3175
|
});
|
|
3000
|
-
this
|
|
3001
|
-
safeDetectChanges(this
|
|
3176
|
+
this.portalContentView = this.portalContentAnchor.createEmbeddedView(this.portalContentTemplate);
|
|
3177
|
+
safeDetectChanges(this.portalContentView);
|
|
3002
3178
|
this.portalContentRendered = true;
|
|
3003
3179
|
}
|
|
3004
3180
|
onBeforeRender(portal) {
|
|
3005
3181
|
this.beforeRender.emit({
|
|
3006
|
-
root: { ...this
|
|
3182
|
+
root: { ...this.parentStore.get(), delta: portal.delta, frame: portal.frame },
|
|
3007
3183
|
portal,
|
|
3008
3184
|
});
|
|
3009
3185
|
}
|
|
3010
|
-
|
|
3186
|
+
inject(rootState, injectState) {
|
|
3011
3187
|
const intersect = { ...rootState };
|
|
3012
3188
|
Object.keys(intersect).forEach((key) => {
|
|
3013
3189
|
if (privateKeys.includes(key) ||
|
|
@@ -3015,7 +3191,7 @@ class NgtPortal extends NgtSignalStore {
|
|
|
3015
3191
|
delete intersect[key];
|
|
3016
3192
|
}
|
|
3017
3193
|
});
|
|
3018
|
-
const inputs = this.get();
|
|
3194
|
+
const inputs = this.inputs.get();
|
|
3019
3195
|
const { size, events, ...restInputsState } = inputs.state || {};
|
|
3020
3196
|
let viewport = undefined;
|
|
3021
3197
|
if (injectState && size) {
|
|
@@ -3027,53 +3203,54 @@ class NgtPortal extends NgtSignalStore {
|
|
|
3027
3203
|
return {
|
|
3028
3204
|
...intersect,
|
|
3029
3205
|
scene: is.ref(inputs.container) ? inputs.container.nativeElement : inputs.container,
|
|
3030
|
-
raycaster: this
|
|
3031
|
-
pointer: this
|
|
3032
|
-
|
|
3206
|
+
raycaster: this.raycaster,
|
|
3207
|
+
pointer: this.pointer,
|
|
3208
|
+
previousRoot: this.parentStore,
|
|
3033
3209
|
events: { ...rootState.events, ...(injectState?.events || {}), ...events },
|
|
3034
3210
|
size: { ...rootState.size, ...size },
|
|
3035
3211
|
viewport: { ...rootState.viewport, ...(viewport || {}) },
|
|
3036
3212
|
...restInputsState,
|
|
3037
3213
|
};
|
|
3038
3214
|
}
|
|
3039
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
3040
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3215
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtPortal, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3216
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.2", 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: `
|
|
3217
|
+
<ng-container #portalContentAnchor>
|
|
3218
|
+
<ng-container
|
|
3219
|
+
*ngIf="autoRender && portalContentRendered"
|
|
3220
|
+
ngtPortalBeforeRender
|
|
3221
|
+
[renderPriority]="autoRenderPriority"
|
|
3222
|
+
[parentScene]="parentScene"
|
|
3223
|
+
[parentCamera]="parentCamera"
|
|
3224
|
+
(beforeRender)="onBeforeRender($event)"
|
|
3225
|
+
/>
|
|
3226
|
+
</ng-container>
|
|
3227
|
+
`, 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"] }] }); }
|
|
3052
3228
|
}
|
|
3053
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
3229
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtPortal, decorators: [{
|
|
3054
3230
|
type: Component,
|
|
3055
3231
|
args: [{
|
|
3056
3232
|
selector: 'ngt-portal',
|
|
3057
3233
|
standalone: true,
|
|
3058
3234
|
template: `
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3235
|
+
<ng-container #portalContentAnchor>
|
|
3236
|
+
<ng-container
|
|
3237
|
+
*ngIf="autoRender && portalContentRendered"
|
|
3238
|
+
ngtPortalBeforeRender
|
|
3239
|
+
[renderPriority]="autoRenderPriority"
|
|
3240
|
+
[parentScene]="parentScene"
|
|
3241
|
+
[parentCamera]="parentCamera"
|
|
3242
|
+
(beforeRender)="onBeforeRender($event)"
|
|
3243
|
+
/>
|
|
3244
|
+
</ng-container>
|
|
3245
|
+
`,
|
|
3070
3246
|
imports: [NgIf, NgtPortalBeforeRender],
|
|
3071
|
-
providers: [
|
|
3247
|
+
providers: [{ provide: NGT_STORE, useFactory: () => signalStore({}) }],
|
|
3072
3248
|
}]
|
|
3073
3249
|
}], ctorParameters: function () { return []; }, propDecorators: { container: [{
|
|
3074
3250
|
type: Input
|
|
3075
|
-
}],
|
|
3076
|
-
type: Input
|
|
3251
|
+
}], portalState: [{
|
|
3252
|
+
type: Input,
|
|
3253
|
+
args: ['state']
|
|
3077
3254
|
}], autoRender: [{
|
|
3078
3255
|
type: Input
|
|
3079
3256
|
}], autoRenderPriority: [{
|
|
@@ -3097,15 +3274,19 @@ class NgtRoutedScene {
|
|
|
3097
3274
|
.pipe(filter((event) => event instanceof ActivationEnd), takeUntilDestroyed())
|
|
3098
3275
|
.subscribe(() => safeDetectChanges(cdr));
|
|
3099
3276
|
}
|
|
3100
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.
|
|
3101
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.
|
|
3277
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtRoutedScene, deps: [{ token: i1.Router }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3278
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.2", type: NgtRoutedScene, isStandalone: true, selector: "ngt-routed-scene", ngImport: i0, template: `
|
|
3279
|
+
<router-outlet />
|
|
3280
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] }); }
|
|
3102
3281
|
}
|
|
3103
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.
|
|
3282
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: NgtRoutedScene, decorators: [{
|
|
3104
3283
|
type: Component,
|
|
3105
3284
|
args: [{
|
|
3106
3285
|
standalone: true,
|
|
3107
3286
|
selector: 'ngt-routed-scene',
|
|
3108
|
-
template:
|
|
3287
|
+
template: `
|
|
3288
|
+
<router-outlet />
|
|
3289
|
+
`,
|
|
3109
3290
|
imports: [RouterOutlet],
|
|
3110
3291
|
}]
|
|
3111
3292
|
}], ctorParameters: function () { return [{ type: i1.Router }, { type: i0.ChangeDetectorRef }]; } });
|
|
@@ -3114,5 +3295,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
|
|
|
3114
3295
|
* Generated bundle index. Do not edit.
|
|
3115
3296
|
*/
|
|
3116
3297
|
|
|
3117
|
-
export {
|
|
3298
|
+
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 };
|
|
3118
3299
|
//# sourceMappingURL=angular-three.mjs.map
|