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:
Said TurkseverandClaude Opus 5.5 committed 2026-10-08 12:55:08 +01:00
1 parent 7bfcf177ac
commit ef396655fc
18 files changed
+505 -110

No files matched your search

+36 -9
View File
@@ -80,8 +80,6 @@ function presentProviders(state) {
else if (keyRequired && provider.requiresKeyId)
title = `${provider.name}: ${keySetupRequirement(provider.requiresKeyId)}`;
else if (provider.error) title = `${provider.name}: ${provider.error}`;
// Usable only on another map stack (Street View off Google 3D).
else if (provider.unavailable) title = provider.unavailable;
return {
id: provider.id,
label: provider.label,
@@ -91,13 +89,11 @@ function presentProviders(state) {
disabled: false,
state: keyRequired
? 'error'
: on && provider.unavailable
? 'warn'
: on && provider.loading
? 'loading'
: on
? 'active'
: 'idle',
: on && provider.loading
? 'loading'
: on
? 'active'
: 'idle',
busy: on && provider.loading === true,
};
});
@@ -134,6 +130,36 @@ function presentViewer(state) {
};
}
/**
* A button for the providers with no coverage to click (Street View): opens
* their nearest image at the view centre, so they need no pointer.
*/
function presentNearest(state) {
const targets = (state.providers || []).filter(
(provider) =>
provider.on && provider.groundClick && provider.keyRequired !== true,
);
if (state.enabled !== true || !targets.length)
return {
visible: false,
label: '',
title: '',
disabled: true,
providerIds: [],
};
const names = targets.map((provider) => provider.name).join(' or ');
const ready = state.groundClickReady === true;
return {
visible: true,
label: `OPEN ${targets.map((provider) => provider.label).join(' / ')}`,
title: ready
? `Open ${names} at the centre of the view`
: `Zoom in to a street to open ${names} here`,
disabled: !ready || state.street.loading === true,
providerIds: targets.map((provider) => provider.id),
};
}
function presentMeta(state) {
if (!state.enabled) return 'Switch a provider on to draw its coverage.';
if (state.sequence.selectedId)
@@ -173,6 +199,7 @@ export function presentStreetLevelPanel(state, { now = Date.now() } = {}) {
legend: state.legend || [],
viewer: presentViewer(state),
meta: presentMeta(state),
nearest: presentNearest(state),
wantsOpen: state.street.open === true,
};
}