Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 154e9b9

Browse files
committed
refactor(core): some perf improvements
1 parent 3491191 commit 154e9b9

File tree

4 files changed

+80
-20
lines changed

4 files changed

+80
-20
lines changed

libs/core/src/lib/events.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,10 @@ export function createEvents(store: SignalState<NgtState>) {
324324
};
325325
}
326326

327+
const isPointerMove = name === 'pointermove';
328+
const isClickEvent = name === 'click' || name === 'contextmenu' || name === 'dblclick';
329+
const filter = isPointerMove ? filterPointerEvents : undefined;
330+
327331
// Any other pointer goes here ...
328332
return function handleEvent(event: NgtDomEvent) {
329333
// NOTE: __pointerMissed$ on NgtStore is private subject since we only expose the Observable
@@ -334,10 +338,6 @@ export function createEvents(store: SignalState<NgtState>) {
334338
internal.lastEvent.nativeElement = event;
335339

336340
// Get fresh intersects
337-
const isPointerMove = name === 'pointermove';
338-
const isClickEvent = name === 'click' || name === 'contextmenu' || name === 'dblclick';
339-
const filter = isPointerMove ? filterPointerEvents : undefined;
340-
341341
const hits = intersect(event, filter);
342342
const delta = isClickEvent ? calculateDistance(event) : 0;
343343

libs/core/src/lib/instance.ts

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export function prepare<TInstance extends NgtAnyRecord = NgtAnyRecord>(
6868
return _nonObjects;
6969
});
7070

71+
instance.__ngt_id__ = crypto.randomUUID();
7172
instance.__ngt__ = {
7273
previousAttach: null,
7374
type,
@@ -195,11 +196,52 @@ export function prepare<TInstance extends NgtAnyRecord = NgtAnyRecord>(
195196
return instance;
196197
}
197198

199+
interface NotificationCacheState {
200+
skipCount: number;
201+
lastType: 'objects' | 'nonObjects';
202+
}
203+
204+
const notificationCache = new Map<string, NotificationCacheState>();
205+
206+
/**
207+
* Notify ancestors about changes to a THREE.js objects' children
208+
*
209+
* For example: `NgtsCenter` might have a child that asynchronously loads a 3D model
210+
* in which case the model matrices will be settled later. `NgtsCenter` needs to know about this
211+
* matrices change to re-center everything inside of it.
212+
*
213+
* The implementation here uses a naive approach to reduce the number of notifications; we cache
214+
* the notifications by the instance ID and the type of the notification.
215+
*
216+
* 1. If there's no cache or
217+
* 2. If the type is different for the same instance or
218+
* 3. We've skipped the notifications for this instance more than a certain amount
219+
*
220+
* then we'll proceed with notification
221+
*/
198222
function notifyAncestors(instance: NgtInstanceNode | null, type: 'objects' | 'nonObjects') {
199223
if (!instance) return;
224+
200225
const localState = getInstanceState(instance);
201226
if (!localState) return;
202-
const { parent } = localState.hierarchyStore.snapshot;
203-
localState.hierarchyStore.update({ [type]: (localState.hierarchyStore.snapshot[type] || []).slice() });
204-
notifyAncestors(parent, type);
227+
228+
const id = instance.__ngt_id__ || instance['uuid'];
229+
if (!id) return;
230+
231+
const cached = notificationCache.get(id);
232+
233+
if (!cached || cached.lastType !== type || cached.skipCount > 5) {
234+
notificationCache.set(id, { skipCount: 0, lastType: type });
235+
236+
if (notificationCache.size === 1) {
237+
queueMicrotask(() => notificationCache.clear());
238+
}
239+
240+
const { parent } = localState.hierarchyStore.snapshot;
241+
localState.hierarchyStore.update({ [type]: (localState.hierarchyStore.snapshot[type] || []).slice() });
242+
notifyAncestors(parent, type);
243+
return;
244+
}
245+
246+
notificationCache.set(id, { ...cached, skipCount: cached.skipCount + 1 });
205247
}

libs/core/src/lib/store.ts

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ export function storeFactory() {
3434

3535
const pointer = new THREE.Vector2();
3636

37+
// getCurrentViewport will mutate this instead of creating a new object everytime
38+
const tempViewport = {
39+
width: 0,
40+
height: 0,
41+
top: 0,
42+
left: 0,
43+
factor: 1,
44+
distance: 0,
45+
aspect: 0,
46+
};
47+
3748
const store: SignalState<NgtState> = signalState<NgtState>({
3849
id: makeId(),
3950
pointerMissed$: pointerMissed$.asObservable(),
@@ -108,22 +119,28 @@ export function storeFactory() {
108119

109120
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
110121

122+
// Update the pre-allocated viewport object
123+
tempViewport.top = top;
124+
tempViewport.left = left;
125+
tempViewport.aspect = aspect;
126+
tempViewport.distance = distance;
127+
111128
if (is.three<THREE.OrthographicCamera>(camera, 'isOrthographicCamera')) {
112-
return {
113-
width: width / camera.zoom,
114-
height: height / camera.zoom,
115-
top,
116-
left,
117-
factor: 1,
118-
distance,
119-
aspect,
120-
};
129+
// For orthographic cameras
130+
tempViewport.width = width / camera.zoom;
131+
tempViewport.height = height / camera.zoom;
132+
tempViewport.factor = 1;
133+
} else {
134+
// For perspective cameras
135+
const fov = (camera.fov * Math.PI) / 180; // convert vertical fov to radians
136+
const h = 2 * Math.tan(fov / 2) * distance; // visible height
137+
const w = h * aspect; // visible width
138+
tempViewport.width = w;
139+
tempViewport.height = h;
140+
tempViewport.factor = width / w;
121141
}
122142

123-
const fov = (camera.fov * Math.PI) / 180; // convert vertical fov to radians
124-
const h = 2 * Math.tan(fov / 2) * distance; // visible height
125-
const w = h * (width / height);
126-
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
143+
return tempViewport;
127144
},
128145
},
129146

libs/core/src/lib/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ export interface NgtInstanceState<TObject extends NgtAnyRecord = NgtAnyRecord> {
238238
}
239239

240240
export type NgtInstanceNode<TObject extends NgtAnyRecord = NgtAnyRecord> = TObject & {
241+
__ngt_id__: string;
241242
__ngt__: NgtInstanceState<TObject>;
242243
};
243244

0 commit comments

Comments
 (0)