mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
Drop the late feature changes of deleted Navara vector layers, which kept the view from going idle
This commit is contained in:
1 parent
843c4a111d
commit
e1d3a588fc
5 files changed
+85
-1
No files matched your search
@@ -3700,6 +3700,7 @@
|
|||||||
"src/globe/navara/index.js",
|
"src/globe/navara/index.js",
|
||||||
"src/globe/navara/input.js",
|
"src/globe/navara/input.js",
|
||||||
"src/globe/navara/internals.js",
|
"src/globe/navara/internals.js",
|
||||||
|
"src/globe/navara/featureQueue.js",
|
||||||
"src/globe/navara/look.js",
|
"src/globe/navara/look.js",
|
||||||
"src/globe/navara/maps.js",
|
"src/globe/navara/maps.js",
|
||||||
"src/globe/navara/sharpen.js",
|
"src/globe/navara/sharpen.js",
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ function rayRaisedEllipsoid({ origin, direction }, height) {
|
|||||||
/**
|
/**
|
||||||
* @param {object} view An initialised Navara ThreeView.
|
* @param {object} view An initialised Navara ThreeView.
|
||||||
* @param {{
|
* @param {{
|
||||||
* hooks: { tileRoots: Function, isIdle: Function, retainTileGeometry: Function },
|
* hooks: { tileRoots: Function, isIdle: Function, retainTileGeometry: Function, dropOrphanFeatureChanges?: Function },
|
||||||
* container?: HTMLElement,
|
* container?: HTMLElement,
|
||||||
* fetch?: typeof fetch,
|
* fetch?: typeof fetch,
|
||||||
* clock?: object,
|
* clock?: object,
|
||||||
@@ -196,6 +196,8 @@ export function createNavaraEngine(
|
|||||||
let drawing = false;
|
let drawing = false;
|
||||||
const handlers = {
|
const handlers = {
|
||||||
preUpdate: (time) => {
|
preUpdate: (time) => {
|
||||||
|
// Before the view decides whether it is idle (internals.js).
|
||||||
|
hooks.dropOrphanFeatureChanges?.();
|
||||||
engineClock.beginFrame();
|
engineClock.beginFrame();
|
||||||
frames.preUpdate.raiseEvent(time);
|
frames.preUpdate.raiseEvent(time);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Logic over a Navara view internal that internals.js reads (the queued
|
||||||
|
// feature changes), kept apart so Node tests can load it without the SDK.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop the queued feature changes of vector layers that no longer exist, and
|
||||||
|
* return how many went. Navara processes a change only for a feature it
|
||||||
|
* knows, and keeps any other in its queue for good: a change that arrives
|
||||||
|
* after its layer was deleted (a polygon display replacing its layers while
|
||||||
|
* their tiles are still being cut) leaves the queue non-empty, so the view
|
||||||
|
* never goes idle and tilesLoaded() stays false.
|
||||||
|
* @param {{ events: object[], remove: (index: number) => void } | null} queue
|
||||||
|
* The queued changes (internals.js featureChangeQueue).
|
||||||
|
* @param {(layerId: string) => boolean} layerExists
|
||||||
|
*/
|
||||||
|
export function dropOrphanFeatureChanges(queue, layerExists) {
|
||||||
|
if (!queue?.events.length) return 0;
|
||||||
|
let dropped = 0;
|
||||||
|
for (let index = queue.events.length - 1; index >= 0; index--) {
|
||||||
|
const event = queue.events[index];
|
||||||
|
const layerId = event?.layer_id;
|
||||||
|
if (layerId == null || layerExists(String(layerId))) continue;
|
||||||
|
queue.remove(index);
|
||||||
|
event.free?.();
|
||||||
|
dropped++;
|
||||||
|
}
|
||||||
|
return dropped;
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import { ModelMesh } from '@navaramap/three';
|
import { ModelMesh } from '@navaramap/three';
|
||||||
import { patchCascadedLightCopy } from './cascadedLightCopy.js';
|
import { patchCascadedLightCopy } from './cascadedLightCopy.js';
|
||||||
|
import { dropOrphanFeatureChanges } from './featureQueue.js';
|
||||||
|
|
||||||
export const NAVARA_INTERNALS_VERSION = '0.2.1';
|
export const NAVARA_INTERNALS_VERSION = '0.2.1';
|
||||||
|
|
||||||
@@ -156,11 +157,35 @@ export function keepCascadedLightIds(view) {
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The view's queued feature changes, for featureQueue.js, or null. Navara
|
||||||
|
* keeps a change for a feature it does not know in that queue for good, so
|
||||||
|
* a deleted layer's late changes keep the view from going idle. Private:
|
||||||
|
* view._eventManager (stacks, removeAt). Upstream ask: drop a deleted
|
||||||
|
* layer's pending feature events, or skip them in needsUpdate.
|
||||||
|
*/
|
||||||
|
export function featureChangeQueue(view) {
|
||||||
|
const manager = view._eventManager;
|
||||||
|
const events = manager?.stacks?.renderable_feature_changed;
|
||||||
|
return events
|
||||||
|
? {
|
||||||
|
events,
|
||||||
|
remove: (index) =>
|
||||||
|
manager.removeAt('renderable_feature_changed', index),
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
/** The hooks createNavaraEngine takes. */
|
/** The hooks createNavaraEngine takes. */
|
||||||
export const navaraHooks = (view) => ({
|
export const navaraHooks = (view) => ({
|
||||||
retainTileGeometry,
|
retainTileGeometry,
|
||||||
tileRoots: () => tileRoots(view),
|
tileRoots: () => tileRoots(view),
|
||||||
isIdle: () => isIdle(view),
|
isIdle: () => isIdle(view),
|
||||||
|
dropOrphanFeatureChanges: () =>
|
||||||
|
dropOrphanFeatureChanges(
|
||||||
|
featureChangeQueue(view),
|
||||||
|
(id) => view.findLayerById(id) != null,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -44,3 +44,32 @@ test('only internals.js reaches private Navara members', () => {
|
|||||||
);
|
);
|
||||||
assert.deepEqual(offenders, []);
|
assert.deepEqual(offenders, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('feature changes of a deleted vector layer leave the queue; live ones stay', async () => {
|
||||||
|
const { dropOrphanFeatureChanges } = await import('./featureQueue.js');
|
||||||
|
const freed = [];
|
||||||
|
const change = (layerId) => ({
|
||||||
|
layer_id: layerId,
|
||||||
|
free: () => freed.push(layerId),
|
||||||
|
});
|
||||||
|
const events = [change('gone'), change('live'), change('gone'), change(null)];
|
||||||
|
const queue = { events, remove: (index) => events.splice(index, 1) };
|
||||||
|
assert.equal(
|
||||||
|
dropOrphanFeatureChanges(queue, (id) => id === 'live'),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
assert.deepEqual(
|
||||||
|
events.map((event) => event.layer_id),
|
||||||
|
['live', null],
|
||||||
|
);
|
||||||
|
assert.deepEqual(freed, ['gone', 'gone']);
|
||||||
|
// No queue, or an empty one, costs nothing.
|
||||||
|
assert.equal(
|
||||||
|
dropOrphanFeatureChanges(null, () => false),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
dropOrphanFeatureChanges({ events: [], remove() {} }, () => false),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
});
|
||||||
Reference in new issue
Block a user