mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 07:42:23 +00:00
Keep fire and camera selections bound to their source records
This commit is contained in:
1 parent
b01f1ee7dc
commit
c4a97a653c
7 files changed
+220
-31
No files matched your search
@@ -219,7 +219,7 @@ export function createApplicationCatalog({
|
||||
],
|
||||
[
|
||||
'alpr-cameras',
|
||||
() => createApplicationAlpr({ surface, source: sources.alpr }),
|
||||
() => sessionModel('alpr-cameras', () => createApplicationAlpr({ surface, source: sources.alpr })),
|
||||
],
|
||||
[
|
||||
'street-level',
|
||||
@@ -326,14 +326,14 @@ export function createApplicationCatalog({
|
||||
[
|
||||
'local-firms',
|
||||
() =>
|
||||
createApplicationFirms({
|
||||
sessionModel('local-firms', () => createApplicationFirms({
|
||||
surface,
|
||||
id: 'local-firms',
|
||||
name: 'FIRMS Active Fires',
|
||||
icon: '▲',
|
||||
source: 'NASA FIRMS · LIVE',
|
||||
feed: sources.firms,
|
||||
}),
|
||||
})),
|
||||
],
|
||||
];
|
||||
const available = (id) => availability.isAvailable(id);
|
||||
|
||||
@@ -68,6 +68,7 @@ export function createAlprCamerasLayer({
|
||||
renderSaturated: false,
|
||||
};
|
||||
let renderer = null;
|
||||
let restoringView = false;
|
||||
|
||||
function setAlprStatus(status, error = null) {
|
||||
if (state.status === status && state.error === error) return;
|
||||
@@ -112,7 +113,7 @@ export function createAlprCamerasLayer({
|
||||
}
|
||||
|
||||
function scheduleLoad() {
|
||||
if (!state.enabled) return;
|
||||
if (!state.enabled || !renderer || restoringView) return;
|
||||
clearUnavailableRetry({ resetBackoff: false });
|
||||
clearTimeout(state.debounceTimer);
|
||||
// A view the accepted tiles already cover is a local filter: show it now.
|
||||
@@ -130,7 +131,7 @@ export function createAlprCamerasLayer({
|
||||
}
|
||||
|
||||
async function loadCameras() {
|
||||
if (!state.enabled || !renderer?.ready) return;
|
||||
if (!state.enabled || !renderer?.ready || restoringView) return;
|
||||
clearTimeout(state.debounceTimer);
|
||||
state.debounceTimer = null;
|
||||
clearUnavailableRetry({ resetBackoff: false });
|
||||
@@ -197,14 +198,14 @@ export function createAlprCamerasLayer({
|
||||
state.lastQueryBox = null;
|
||||
state.lastQueryZoom = null;
|
||||
clearUnavailableRetry();
|
||||
renderer.renderRecords();
|
||||
if (!restoringView) renderer?.renderRecords();
|
||||
setAlprStatus('zoom-in');
|
||||
return;
|
||||
}
|
||||
const { records, stale, saturated } = validateAlprSnapshot(snapshot);
|
||||
// Resolve marker floors (bounded wait, warm cells answer at once) so new
|
||||
// markers are placed on the floor instead of clamped then moved.
|
||||
await renderer.prepareFloors(records);
|
||||
await renderer?.prepareFloors(records);
|
||||
if (
|
||||
requestAbort.signal.aborted ||
|
||||
state.abort !== requestAbort ||
|
||||
@@ -230,8 +231,8 @@ export function createAlprCamerasLayer({
|
||||
clearUnavailableRetry();
|
||||
// Stale and saturated are independent facts; a cached response that also
|
||||
// hit the cap must still warn about coverage, not just about freshness.
|
||||
renderer.renderRecords();
|
||||
setAlprStatus(renderer.count() ? (stale ? 'stale' : 'ready') : 'empty');
|
||||
if (!restoringView) renderer?.renderRecords();
|
||||
setAlprStatus((renderer?.count() ?? records.length) ? (stale ? 'stale' : 'ready') : 'empty');
|
||||
} catch (error) {
|
||||
if (
|
||||
error?.name === 'AbortError' ||
|
||||
@@ -265,7 +266,11 @@ export function createAlprCamerasLayer({
|
||||
source: source.label || msg('Mapped camera locations'),
|
||||
updateInterval: 0,
|
||||
statsRefreshInterval: 1000,
|
||||
init(viewer, options = {}) {
|
||||
init(viewer, options) {
|
||||
this.attachRenderer(viewer, options);
|
||||
},
|
||||
attachRenderer(viewer, options = {}) {
|
||||
restoringView = Boolean(options.waitForCameraRestore);
|
||||
if (renderer?.ready) throw new Error('ALPR layer is already initialized');
|
||||
if (typeof rendererFactory !== 'function')
|
||||
throw new TypeError('An ALPR renderer factory is required');
|
||||
@@ -276,6 +281,24 @@ export function createAlprCamerasLayer({
|
||||
engine: options.engine,
|
||||
});
|
||||
renderer.init(viewer, { onMove: scheduleLoad });
|
||||
if (state.enabled) {
|
||||
renderer.setVisible(true);
|
||||
if (!restoringView) renderer.renderRecords();
|
||||
}
|
||||
},
|
||||
detachRenderer() {
|
||||
restoringView = true;
|
||||
clearTimeout(state.debounceTimer);
|
||||
renderer?.destroy({ retainContext: true });
|
||||
renderer = null;
|
||||
},
|
||||
resumeViewport() {
|
||||
if (!restoringView) return;
|
||||
restoringView = false;
|
||||
if (state.enabled && renderer) {
|
||||
renderer.renderRecords();
|
||||
if (!state.loading) scheduleLoad();
|
||||
}
|
||||
},
|
||||
enable() {
|
||||
if (state.enabled) return;
|
||||
|
||||
@@ -44,7 +44,7 @@ export function createAlprCesiumRenderer({ state, services, source }) {
|
||||
if (visible) native.creditPresented = false;
|
||||
if (native.dataSource) native.dataSource.show = visible;
|
||||
},
|
||||
destroy() {
|
||||
destroy(options) {
|
||||
presentation.destroyOverlay();
|
||||
removeMove?.();
|
||||
removeMove = null;
|
||||
@@ -52,7 +52,7 @@ export function createAlprCesiumRenderer({ state, services, source }) {
|
||||
removeFrame = null;
|
||||
native.clickHandler?.destroy();
|
||||
native.clickHandler = null;
|
||||
presentation.clearRendered();
|
||||
presentation.clearRendered(options);
|
||||
if (native.dataSource && native.viewer)
|
||||
native.viewer.dataSources.remove(native.dataSource, true);
|
||||
native.dataSource = null;
|
||||
|
||||
@@ -304,7 +304,7 @@ export function createAlprPresentation({ state, native, services, source }) {
|
||||
return { south, west, north, east };
|
||||
}
|
||||
|
||||
function clearRendered() {
|
||||
function clearRendered({ retainContext = false } = {}) {
|
||||
hideOnMapCredit();
|
||||
floors.cancel();
|
||||
floorResolve = null;
|
||||
@@ -312,7 +312,7 @@ export function createAlprPresentation({ state, native, services, source }) {
|
||||
visibleRecords = [];
|
||||
clampedMarkers.clear();
|
||||
if (native.dataSource?.entities) native.dataSource.entities.removeAll();
|
||||
removeEntityContextsForLayer(LAYER_ID);
|
||||
if (!retainContext) removeEntityContextsForLayer(LAYER_ID);
|
||||
}
|
||||
|
||||
function hideOnMapCredit() {
|
||||
|
||||
@@ -449,7 +449,7 @@ export function createAlprNavaraRenderer(engine, { state, services, source }) {
|
||||
else hideOnMapCredit();
|
||||
request();
|
||||
}
|
||||
function clearRendered() {
|
||||
function clearRendered({ retainContext = false } = {}) {
|
||||
hideOnMapCredit();
|
||||
generation++;
|
||||
floors.cancel();
|
||||
@@ -464,7 +464,7 @@ export function createAlprNavaraRenderer(engine, { state, services, source }) {
|
||||
selected.commit();
|
||||
spritesDirty = false;
|
||||
}
|
||||
services.context.removeEntityContextsForLayer(LAYER_ID);
|
||||
if (!retainContext) services.context.removeEntityContextsForLayer(LAYER_ID);
|
||||
}
|
||||
function frame() {
|
||||
const camera = engine.camera.livePosition;
|
||||
@@ -582,9 +582,9 @@ export function createAlprNavaraRenderer(engine, { state, services, source }) {
|
||||
request();
|
||||
return true;
|
||||
},
|
||||
destroy() {
|
||||
destroy(options) {
|
||||
if (!initialized) return;
|
||||
clearRendered();
|
||||
clearRendered(options);
|
||||
overlay.destroy();
|
||||
removeClick?.();
|
||||
removeClick = null;
|
||||
|
||||
@@ -12,7 +12,10 @@ export function createLifecycle({
|
||||
const { id, overlayHost } = config;
|
||||
|
||||
const methods = {
|
||||
init(viewer, { engine = null } = {}) {
|
||||
init(viewer, options) {
|
||||
this.attachRenderer(viewer, options);
|
||||
},
|
||||
attachRenderer(viewer, { engine = null, waitForCameraRestore = false } = {}) {
|
||||
if (layerState._destroyed) return;
|
||||
if (layerState._renderer) return;
|
||||
layerState._renderer = config.renderer.create({
|
||||
@@ -25,14 +28,36 @@ export function createLifecycle({
|
||||
layerState._viewer = layerState._renderer.view;
|
||||
layerState._dataSource = layerState._renderer.dataSource;
|
||||
layerState._renderer.setVisible(false);
|
||||
layerState._restoringViewport = waitForCameraRestore;
|
||||
if (layerState._enabled && !waitForCameraRestore) {
|
||||
this.showRenderer();
|
||||
layerState._renderer.onEnable();
|
||||
}
|
||||
},
|
||||
|
||||
async enable(viewer) {
|
||||
if (layerState._destroyed) return;
|
||||
layerState._enabled = true;
|
||||
if (!layerState._dataSource) this.init(viewer);
|
||||
const renderer = layerState._renderer;
|
||||
layerState._viewer = layerState._renderer.view;
|
||||
resumeViewport() {
|
||||
if (!layerState._restoringViewport) return;
|
||||
layerState._restoringViewport = false;
|
||||
if (layerState._enabled && layerState._renderer) {
|
||||
this.showRenderer();
|
||||
layerState._renderer.onEnable();
|
||||
}
|
||||
},
|
||||
|
||||
detachRenderer() {
|
||||
components.selection.removeClickHandler();
|
||||
components.viewport.removeMoveEndWatcher();
|
||||
components.viewport.removeLodWatcher();
|
||||
unregisterPickOwner(id);
|
||||
components.rendering.removeDetectionCollections(layerState._viewer);
|
||||
layerState._renderer?.destroy();
|
||||
layerState._renderer = layerState._viewer = layerState._dataSource = null;
|
||||
layerState._pickIndexById.clear();
|
||||
layerState._labelCandidates = [];
|
||||
layerState._camSnapValid = false;
|
||||
},
|
||||
|
||||
showRenderer() {
|
||||
if (layerState._billboards) {
|
||||
// The camera can have moved anywhere while the layer was off: moveEnd
|
||||
// was not being listened to, and the preRender watcher is inert while
|
||||
@@ -51,14 +76,18 @@ export function createLifecycle({
|
||||
registerPickOwner(id, (pickedId) =>
|
||||
layerState._pickIndexById.has(pickedId),
|
||||
);
|
||||
components.rendering.renderCurrentLod(true);
|
||||
},
|
||||
|
||||
async enable(viewer) {
|
||||
if (layerState._destroyed) return;
|
||||
if (!layerState._dataSource) this.init(viewer);
|
||||
layerState._enabled = true;
|
||||
const renderer = layerState._renderer;
|
||||
this.showRenderer();
|
||||
if (!layerState._fires.length && !layerState._loading)
|
||||
await components.ingestion.loadHeatmap();
|
||||
if (
|
||||
layerState._enabled &&
|
||||
!layerState._destroyed &&
|
||||
layerState._renderer === renderer
|
||||
)
|
||||
renderer.onEnable();
|
||||
if (layerState._enabled && layerState._renderer === renderer) renderer.onEnable();
|
||||
},
|
||||
|
||||
disable() {
|
||||
|
||||
Reference in new issue
Block a user