mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
feat(street-level): OPEN STREET VIEW, and Street View only on Google 3D
- OPEN STREET VIEW in the PROVIDERS row opens Street View's nearest panorama at the ground under the middle of the screen, without moving the camera: Street View no longer needs a pointer. It is disabled (and says so) until the camera is at street zoom. - Off the Google 3D map Street View does not appear at all: no chip, legend swatch, globe credit, layer source or button, and Google's script is not loaded (the viewer has no prewarm; the script loads on first use). The share option keeps the user's choice for when Google 3D returns. - A ground click measures the camera height at the click rather than reading the cached flag. - A chip without a usable key explains it instead of lighting; it darkens beside a lit chip, and the other chips keep switching, so a refused Street View key cannot lock Mapillary out. - The gate checks that nothing of Street View shows off Google 3D even when a share link switches it on, presses OPEN STREET VIEW on Google 3D, and asserts that each chip it switches really switched. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
7bfcf177ac
commit
ef396655fc
18 files changed
+505
-110
No files matched your search
@@ -502,15 +502,16 @@ async function withStreetView(t, { mapStack = 'photoreal', nearest } = {}) {
|
||||
},
|
||||
});
|
||||
mapillary.requiresKeyId = 'mapillary';
|
||||
const loader = fakeMapsLoader(fake.library);
|
||||
const google = createGoogleProvider({
|
||||
getApiKey: () => 'browser-key',
|
||||
loader: fakeMapsLoader(fake.library),
|
||||
loader,
|
||||
});
|
||||
const { layer, viewer } = await enabledLayer(t, [mapillary, google]);
|
||||
const stack = fakeMapStack(mapStack);
|
||||
layer.attachMapStackController(stack);
|
||||
layer.attachViewerHost(fakeHost());
|
||||
return { layer, viewer, stack, fake, mapillaryLookups };
|
||||
return { layer, viewer, stack, fake, loader, mapillaryLookups };
|
||||
}
|
||||
|
||||
test('Street View starts off, and the layer row names the key of the providers that are on', async (t) => {
|
||||
@@ -523,27 +524,42 @@ test('Street View starts off, and the layer row names the key of the providers t
|
||||
assert.equal(layer.requiresKeyId, null, 'two keys: each chip names its own');
|
||||
});
|
||||
|
||||
test('Street View opens only on the Google 3D map, and leaving that map closes it', async (t) => {
|
||||
const { layer, stack } = await withStreetView(t, {
|
||||
test('Street View appears only on the Google 3D map: chip, legend, credit, source and images', async (t) => {
|
||||
const { layer, viewer, stack } = await withStreetView(t, {
|
||||
mapStack: 'esri-imagery',
|
||||
});
|
||||
layer.setProviderEnabled('google', true);
|
||||
await settle();
|
||||
const google = () =>
|
||||
layer.getUIState().providers.find((p) => p.id === 'google');
|
||||
assert.match(google().unavailable, /needs the Google 3D map/);
|
||||
assert.equal(google().hint, '', 'no "click a street" off Google 3D');
|
||||
const ui = () => layer.getUIState();
|
||||
const listed = () => ui().providers.map((p) => p.id);
|
||||
const credited = () =>
|
||||
viewer.credits.some((credit) => /Street View imagery/.test(credit.html));
|
||||
assert.deepEqual(listed(), ['mapillary'], 'no Street View chip');
|
||||
assert.ok(!ui().legend.some((item) => item.key === 'google'));
|
||||
assert.equal(credited(), false, 'no Google credit on another map');
|
||||
assert.equal(layer.source, 'Mapillary');
|
||||
assert.equal(layer.getStats().source, 'Mapillary');
|
||||
assert.equal(await layer.openImage('google', 'pano-a'), false);
|
||||
assert.match(layer.getUIState().street.error, /needs the Google 3D map/);
|
||||
assert.match(ui().street.error, /needs the Google 3D map/);
|
||||
assert.equal(layer.getParams().google, true, 'the choice is kept');
|
||||
|
||||
stack.switchTo('photoreal');
|
||||
assert.equal(google().unavailable, null);
|
||||
assert.deepEqual(listed(), ['mapillary', 'google']);
|
||||
assert.equal(credited(), true);
|
||||
assert.equal(layer.source, 'Mapillary · Google Street View');
|
||||
assert.equal(await layer.openImage('google', 'pano-a'), true);
|
||||
assert.equal(layer.getUIState().street.providerId, 'google');
|
||||
assert.equal(ui().street.providerId, 'google');
|
||||
|
||||
stack.switchTo('bing');
|
||||
await settle();
|
||||
assert.equal(layer.getUIState().street.open, false, 'closed with the map');
|
||||
assert.equal(ui().street.open, false, 'closed with the map');
|
||||
assert.equal(credited(), false);
|
||||
assert.deepEqual(listed(), ['mapillary']);
|
||||
});
|
||||
|
||||
test('the UI state says when a click (or the button) can open Street View here', async (t) => {
|
||||
const { layer } = await withStreetView(t);
|
||||
assert.equal(typeof layer.getUIState().groundClickReady, 'boolean');
|
||||
});
|
||||
|
||||
test('a lookup for the click-to-open providers asks only them and reports "that point"', async (t) => {
|
||||
@@ -575,3 +591,49 @@ test('an image opened from a ground click leaves the camera where it is', async
|
||||
assert.equal(layer.getUIState().street.imageId, 'pano-a');
|
||||
assert.equal(viewer.flights.started, 0, 'no framing flight');
|
||||
});
|
||||
|
||||
test('off Google 3D not even Google\u2019s script is loaded for Street View', async (t) => {
|
||||
const { layer, loader } = await withStreetView(t, {
|
||||
mapStack: 'esri-imagery',
|
||||
});
|
||||
layer.setProviderEnabled('google', true);
|
||||
layer.attachViewerHost({ ownerDocument: { createElement: () => ({}) } });
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
assert.deepEqual(loader.imports, [], 'no prewarm, no lookup');
|
||||
});
|
||||
|
||||
test('the button’s “centre of the view” is the ground under the middle of the screen', async (t) => {
|
||||
const { createStreetLevelLayer: create } = await import('./index.js');
|
||||
const scenePick = await import('../../data/scenePick.js');
|
||||
const lookups = [];
|
||||
const provider = fakeProvider({
|
||||
nearestImage: async (point) => {
|
||||
lookups.push(point);
|
||||
return null;
|
||||
},
|
||||
});
|
||||
const saved = globalThis.document;
|
||||
const drawing = new Proxy({}, { get: () => () => ({ addColorStop() {} }) });
|
||||
globalThis.document = Object.assign(new EventTarget(), {
|
||||
createElement: () => ({ getContext: () => drawing }),
|
||||
});
|
||||
const viewer = fakeViewer();
|
||||
const centre = Cesium.Cartesian3.fromDegrees(-121.4937, 38.5799, 0);
|
||||
Object.assign(viewer.scene, {
|
||||
pickPositionSupported: true,
|
||||
pickPosition: (at) => (at.x === 500 && at.y === 300 ? centre : undefined),
|
||||
});
|
||||
viewer.scene.canvas.clientWidth = 1000;
|
||||
viewer.scene.canvas.clientHeight = 600;
|
||||
const layer = create({ providers: [provider], services: { scenePick } });
|
||||
layer.init(viewer);
|
||||
layer.enable(viewer);
|
||||
t.after(() => {
|
||||
layer.destroy();
|
||||
globalThis.document = saved;
|
||||
});
|
||||
await layer.openNearest(undefined, { aim: 'screen-centre' });
|
||||
assert.equal(lookups.length, 1);
|
||||
assert.ok(Math.abs(lookups[0].lat - 38.5799) < 1e-9);
|
||||
assert.ok(Math.abs(lookups[0].lon - -121.4937) < 1e-9);
|
||||
});
|
||||
Reference in new issue
Block a user