mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
feat: turn layers on in links to an area
open_in_gods_eye_view accepts layers and writes them with the app's own share-link layer codec, so the link opens with those layers on. Layer names are limited to the registered layer ids.
This commit is contained in:
1 parent
9de2705eaf
commit
fe69f22346
4 files changed
+56
-7
No files matched your search
@@ -1,5 +1,10 @@
|
||||
/** A link that opens God's Eye View on an area. */
|
||||
|
||||
import {
|
||||
REGISTERED_LAYER_IDS,
|
||||
createDefaultLayerState,
|
||||
encodeLayerStateParams,
|
||||
} from '../../data/layerState.js';
|
||||
import { defineTool, ToolError } from '../catalog.js';
|
||||
import { AREA_SCHEMA, areaCenter, areaRadiusKm, resolveArea } from '../area.js';
|
||||
|
||||
@@ -12,10 +17,19 @@ export const openInGodsEyeView = defineTool({
|
||||
name: 'open_in_gods_eye_view',
|
||||
title: "Open in God's Eye View",
|
||||
description:
|
||||
"A link that opens God's Eye View looking straight down on an area.",
|
||||
"A link that opens God's Eye View looking straight down on an area, " +
|
||||
'optionally with chosen data layers turned on.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: { area: AREA_SCHEMA },
|
||||
properties: {
|
||||
area: AREA_SCHEMA,
|
||||
layers: {
|
||||
type: 'array',
|
||||
maxItems: REGISTERED_LAYER_IDS.length,
|
||||
items: { type: 'string', enum: [...REGISTERED_LAYER_IDS] },
|
||||
description: 'Layers to turn on, such as "flights" or "earthquakes".',
|
||||
},
|
||||
},
|
||||
required: ['area'],
|
||||
additionalProperties: false,
|
||||
},
|
||||
@@ -38,18 +52,26 @@ export const openInGodsEyeView = defineTool({
|
||||
),
|
||||
),
|
||||
);
|
||||
// The share-link camera fields; the app restores its defaults for the rest.
|
||||
base.hash = new URLSearchParams({
|
||||
// The share-link camera and layer fields; the app restores its defaults
|
||||
// for everything else.
|
||||
const params = new URLSearchParams({
|
||||
v: '2',
|
||||
lat: center.lat.toFixed(4),
|
||||
lon: center.lon.toFixed(4),
|
||||
alt: String(altitude),
|
||||
heading: '0',
|
||||
pitch: '-90',
|
||||
}).toString();
|
||||
});
|
||||
const layers = [...new Set(args.layers || [])];
|
||||
if (layers.length)
|
||||
encodeLayerStateParams(params, {
|
||||
...createDefaultLayerState(),
|
||||
enabledLayerIds: layers,
|
||||
});
|
||||
base.hash = params.toString();
|
||||
return {
|
||||
summary: `Open ${area.label} in God's Eye View: ${base.href}`,
|
||||
data: { url: base.href, center, altitude_m: altitude },
|
||||
data: { url: base.href, center, altitude_m: altitude, layers },
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -53,3 +53,28 @@ test('altitude is bounded for tiny and planet-sized areas', async () => {
|
||||
(error) => error.code === 'unavailable',
|
||||
);
|
||||
});
|
||||
|
||||
test('links turn on the requested layers with the app share-link codec', async () => {
|
||||
const { decodeLayerStateParams } = await import('../../data/layerState.js');
|
||||
const catalog = composeCatalog({
|
||||
tools: coreTools,
|
||||
services: { app: { baseUrl: 'http://localhost:4173/' } },
|
||||
});
|
||||
const result = await catalog.call('open_in_gods_eye_view', {
|
||||
area: { lat: 30.27, lon: -97.74, radius_km: 10 },
|
||||
layers: ['earthquakes', 'flights', 'flights'],
|
||||
});
|
||||
assert.deepEqual(result.data.layers, ['earthquakes', 'flights']);
|
||||
const params = new URLSearchParams(new URL(result.data.url).hash.slice(1));
|
||||
assert.deepEqual(decodeLayerStateParams(params).enabledLayerIds.sort(), [
|
||||
'earthquakes',
|
||||
'flights',
|
||||
]);
|
||||
await assert.rejects(
|
||||
catalog.call('open_in_gods_eye_view', {
|
||||
area: { lat: 0, lon: 0, radius_km: 1 },
|
||||
layers: ['not-a-layer'],
|
||||
}),
|
||||
/must be one of/,
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user