mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
feat(layers): Recent Imagery — open satellite imagery for a selected box (#716)
Select a box on the world and browse the last 30 days of open satellite imagery over it, keyless: NASA GIBS Harmonized Landsat Sentinel-2 (30 m) and the VIIRS daily overview (250 m), with a day strip, IMAGE / VS BASEMAP / A / B modes with a swipe divider, PNG export and share links. The before/after swipe from the Nepal scene moves into shared modules so both use it. Co-authored-by: manjunath22466 <[email protected]>
This commit is contained in:
1 parent
25491f7e33
commit
082074a006
50 files changed
+13169
-440
No files matched your search
@@ -13,6 +13,7 @@ import { createApplicationRadio } from './layers/radio.js';
|
||||
import { createApplicationTraffic } from './layers/traffic.js';
|
||||
import { createApplicationBikeshare } from './layers/bikeshare.js';
|
||||
import { createApplicationDirections } from './layers/directions.js';
|
||||
import { createApplicationRecentImagery } from './layers/recentImagery.js';
|
||||
import { createApplicationTransit } from './layers/transit.js';
|
||||
import { createApplicationInstallations } from './layers/militaryInstallations.js';
|
||||
import { createApplicationSatellites } from './layers/satellites.js';
|
||||
@@ -129,6 +130,7 @@ export function createApplicationCatalog({
|
||||
createApplicationTransit({ surface, source: sources.transit }),
|
||||
createApplicationBikeshare({ source: sources.bikeshare }),
|
||||
createApplicationDirections(),
|
||||
createApplicationRecentImagery(),
|
||||
vessels,
|
||||
installations,
|
||||
createApplicationAwareness({
|
||||
|
||||
@@ -39,7 +39,7 @@ test('catalogs construct distinct layers and classification from their supplied
|
||||
signal: b.signal,
|
||||
surface: fixtureSurface(b.signal),
|
||||
});
|
||||
assert.equal(first.layers.length, 26);
|
||||
assert.equal(first.layers.length, 27);
|
||||
assert.notEqual(first.weatherClock, second.weatherClock);
|
||||
await first.weatherClock.setTarget('2026-09-21T12:00:00.000Z');
|
||||
assert.match(
|
||||
|
||||
@@ -70,6 +70,12 @@ export class LayerPresentation {
|
||||
mount(container) {
|
||||
this.panel.mount(container);
|
||||
}
|
||||
/** Hand the Recent Imagery readout factory to the panel (see LayerPanel). */
|
||||
attachRecentImagery(factory) {
|
||||
// Detaching never builds a panel that teardown already released.
|
||||
if (factory) this.panel.attachRecentImagery(factory);
|
||||
else this._panel?.attachRecentImagery(null);
|
||||
}
|
||||
refresh() {
|
||||
this._panel?._refreshTogglePanel();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { createRecentImageryLayer } from '../../layers/recentImagery/index.js';
|
||||
import { createRecentImageryRenderer } from '../../layers/recentImagery/rendering.js';
|
||||
import { createThumbnailLoader } from '../../layers/recentImagery/thumbnails.js';
|
||||
import { governorRequestRender } from '../../renderGovernor.js';
|
||||
|
||||
/**
|
||||
* Construct the Recent Imagery layer with the real GIBS renderer and the
|
||||
* browser thumbnail loader. It takes no data source: the catalog is NASA
|
||||
* CMR and the tiles are GIBS, both browser-direct and keyless.
|
||||
* @returns {object} A fresh layer instance for this catalog.
|
||||
*/
|
||||
export function createApplicationRecentImagery() {
|
||||
return createRecentImageryLayer({
|
||||
renderer: createRecentImageryRenderer({
|
||||
requestRender: governorRequestRender,
|
||||
}),
|
||||
thumbnails: createThumbnailLoader(),
|
||||
});
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import { SceneDirector } from '../scenes/director.js';
|
||||
import { initAnnotations } from '../annotations/index.js';
|
||||
import { initDrawTool } from '../annotations/drawTool.js';
|
||||
import { initImageryBoxTool } from '../ui/imageryBoxTool.js';
|
||||
import { createRecentImageryPanel } from '../ui/recentImagery.js';
|
||||
import { initGevVoiceCommands } from '../voice/gevRealtime.js';
|
||||
import { installScopeMask, destroyScopeMask } from '../scopeMask.js';
|
||||
import {
|
||||
@@ -53,6 +55,43 @@ export function createApplicationTools({
|
||||
// lifetime rather than to whoever last pressed the button.
|
||||
const drawTool = initDrawTool({ viewer, annotations });
|
||||
defer(() => drawTool?.destroy());
|
||||
// DATA ▸ Recent Imagery: the box tool claims the pointer like Draw and the
|
||||
// panel lives on the right rail, so both belong to the application
|
||||
// lifetime. The tileset lets the layer drape while the globe is hidden.
|
||||
const recentImagery = dataManager.layers.get('recent-imagery')?.module;
|
||||
if (recentImagery) {
|
||||
recentImagery.attachTileset(tileset);
|
||||
const imageryBoxTool = initImageryBoxTool({
|
||||
viewer,
|
||||
onBox: (box) => recentImagery.setBox(box),
|
||||
onCancel: (reason, message, box) => {
|
||||
if (message) recentImagery.reportBoxRefusal(message, box);
|
||||
},
|
||||
onActive: (active) => recentImagery.setToolActive(active),
|
||||
// The tool takes Escape in a capture listener, so the panel's order
|
||||
// (clear a preview before cancelling the tool) is applied here.
|
||||
onEscape: () => recentImagery.clearPreview(),
|
||||
});
|
||||
// The readout mounts in its rail body through the layer panel, like the
|
||||
// weather readout.
|
||||
data.presentation.attachRecentImagery((container) =>
|
||||
createRecentImageryPanel({
|
||||
container,
|
||||
viewer,
|
||||
layer: recentImagery,
|
||||
tool: imageryBoxTool,
|
||||
}),
|
||||
);
|
||||
// The live gate's handle (scripts/qa-recent-imagery.mjs).
|
||||
const recentImageryHandle = { layer: recentImagery, tool: imageryBoxTool };
|
||||
window.__gevRecentImagery = recentImageryHandle;
|
||||
defer(() => {
|
||||
if (window.__gevRecentImagery === recentImageryHandle)
|
||||
delete window.__gevRecentImagery;
|
||||
data.presentation.attachRecentImagery(null);
|
||||
imageryBoxTool?.destroy();
|
||||
});
|
||||
}
|
||||
if (startChrome)
|
||||
defer(startChrome({ loadingScreen, styleManager, dataManager, signal }));
|
||||
// Idle render governor: flips the scene into requestRenderMode whenever
|
||||
|
||||
Reference in new issue
Block a user