mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-14 15:22:21 +00:00
Street Level: shorter comments and docs
- Comments in the action, the layer, embed, the Mapillary policy and the controls say why in fewer words; restatements of the code are gone. - CURRENT-STATE's "Show me X on Street View" section is a list by topic and no longer says the browser gate aims at coverageLines. - TOOLS.md's street-level view paragraph is shorter.
This commit is contained in:
1 parent
f3996da0af
commit
e34b5103c6
7 files changed
+167
-215
No files matched your search
+19
-31
@@ -183,8 +183,7 @@ function flyTo(viewer, camera) {
|
||||
|
||||
/**
|
||||
* The `show_street_level` arguments for a view's street-level photos. A plain
|
||||
* link (`autoOpen: false`) never loads a photo from a source that bills every
|
||||
* load: the app arms the panel and the OPEN button is one click away. A view
|
||||
* link (`autoOpen: false`) only arms a source that bills every load; a view
|
||||
* posted into the embedded app is the client's own request and opens.
|
||||
*/
|
||||
function streetLevelArgs(streetLevel, { autoOpen = true } = {}) {
|
||||
@@ -260,20 +259,18 @@ export async function applyView(
|
||||
if (view.annotations.length)
|
||||
await act('annotate_map', { annotations: [...view.annotations] });
|
||||
if (view.street_level) {
|
||||
// The photos frame the camera: the action flies to the point at street
|
||||
// level, lights the source and opens the nearest photo. When it fails
|
||||
// before flying, the view's own camera still applies.
|
||||
// The photos frame the camera; when the action fails before flying, the
|
||||
// view's own camera still applies.
|
||||
const result = await act(
|
||||
'show_street_level',
|
||||
streetLevelArgs(view.street_level, { autoOpen }),
|
||||
);
|
||||
if (result?.ok !== true) {
|
||||
// Overtaken (a click on the map, a newer request): the panel and the
|
||||
// camera are someone else's now.
|
||||
// Overtaken (a click on the map, a newer request): hands off.
|
||||
if (result?.cancelled || result?.superseded) return steps;
|
||||
// An earlier view's photo must not stay over a place this view left.
|
||||
// From the imagery stage on the action has settled the panel itself:
|
||||
// a photo it found but could not load keeps its error in view.
|
||||
// From the imagery stage on the action has settled the panel itself
|
||||
// (a photo it could not load keeps its error).
|
||||
if (result?.stage !== 'imagery')
|
||||
dataManager.layers?.get?.(STREET_LEVEL_LAYER)?.module?.closeViewer?.();
|
||||
if (!result?.location)
|
||||
@@ -331,18 +328,13 @@ export function installViews({
|
||||
const hashParams = new URLSearchParams(
|
||||
String(location?.hash || '').replace(/^#/, ''),
|
||||
);
|
||||
// What the link itself asks for runs first, one thing at a time; posted
|
||||
// views queue behind it. One failing step does not take the next with it.
|
||||
// The camera's owner at restore: anyone who navigates while the link's
|
||||
// steps wait (a gesture, a search, the assistant) takes it, and a passive
|
||||
// link must not fly over them.
|
||||
// A start-up restore that a newer link superseded hands the camera to that
|
||||
// link: its own steps never run.
|
||||
// A restore whose camera never landed (the recipient dragged, searched or
|
||||
// opened another place during its flight) leaves the camera with them.
|
||||
// The link's own steps run first, one at a time, and posted views queue
|
||||
// behind them; one failing step does not take the next with it. A passive
|
||||
// link never flies over someone who took the camera: its steps are skipped
|
||||
// when a newer link superseded it, when its flight never landed (the
|
||||
// recipient dragged or searched), or after any navigation since the
|
||||
// generation its restore flight owned.
|
||||
const cameraLanded = (outcome) => outcome?.share?.camera === 'applied';
|
||||
// The generation the restore's own flight owned: a navigation after it
|
||||
// landed, while the layers still loaded, has moved on from it.
|
||||
const restoreGeneration = (outcome) =>
|
||||
Number.isInteger(outcome?.navigationToken)
|
||||
? outcome.navigationToken
|
||||
@@ -369,11 +361,9 @@ export function installViews({
|
||||
const linked = annotationsFromParams(hashParams);
|
||||
if (linked.length)
|
||||
queue = linkStep(() => run('annotate_map', { annotations: linked }));
|
||||
// A link to street-level photos opens them once the link has restored. A
|
||||
// link anyone can publish stops short of a billed load and leaves it to a
|
||||
// click; only the panel page's own link for a result issued just now is
|
||||
// the client's request (a host remounting the panel hands back old ones).
|
||||
// A link that follows an entity keeps the camera on it.
|
||||
// A link's street-level photos open once it has restored. A billed source
|
||||
// only arms, except for the panel page's own link to a result issued just
|
||||
// now. A link that follows an entity keeps the camera on it.
|
||||
const linkedStreetLevel = (params) =>
|
||||
followFromParams(params) ? null : streetLevelFromParams(params);
|
||||
const openLinkedStreetLevel = async (
|
||||
@@ -388,9 +378,8 @@ export function installViews({
|
||||
streetLevelArgs(streetLevel, { autoOpen }),
|
||||
{ origin: 'programmatic' },
|
||||
);
|
||||
// The restore window keeps the panel collapsed; OPEN must be in view.
|
||||
// Embed mode hides the rail that holds it, so there the link only arms
|
||||
// (a posted view is the way to open a photo in a frame).
|
||||
// OPEN must be in view, but embed mode hides the rail that holds it: in
|
||||
// a frame a posted view is the way to open a photo.
|
||||
if (result?.armed === true && !isEmbedded(location)) {
|
||||
shell.setPanelCollapsed?.(STREET_LEVEL_PANEL_ID, false, {
|
||||
explicit: true,
|
||||
@@ -410,9 +399,8 @@ export function installViews({
|
||||
autoOpen: isFreshPanelResult(),
|
||||
}),
|
||||
);
|
||||
// A link pasted into the open tab restores camera and layers on its own;
|
||||
// its photos follow once that restore settles, under the same rule: a plain
|
||||
// link never loads a billed photo by itself.
|
||||
// A link pasted into the open tab: its photos follow once its restore
|
||||
// settles, under the same rules.
|
||||
const onNavigatedRestore = (event) => {
|
||||
if (event?.detail?.status !== 'settled' || !cameraLanded(event.detail))
|
||||
return;
|
||||
|
||||
@@ -697,22 +697,19 @@ export function createStreetLevelLayer({
|
||||
/**
|
||||
* Open the nearest image of the active providers (or `providerIds`) near
|
||||
* a point, else the view centre, or with `aim: 'screen-centre'` the ground
|
||||
* under the screen centre (sky: nothing). `radiusM` widens the search for
|
||||
* providers that can (a geocoded landmark is rarely within 50 m of a
|
||||
* street); clicks keep the default. A caller's `signal` retires the
|
||||
* lookup: nothing opens after it fires. Providers without
|
||||
* `nearestImage` are skipped. `armed: false` (a request of its own, such
|
||||
* as the assistant's) does not use a link's armed point, and keeps it
|
||||
* while it looks; a photo it opens ends it, as any opened photo does. Why
|
||||
* nothing opened is left in `street.nearestOutcome`: 'empty' (no imagery
|
||||
* in reach), 'sky' (the screen centre is not ground), or null (an error).
|
||||
* `replace: true` (a request that takes over the panel) keeps an open
|
||||
* photo up while it looks, so the viewer and EXPAND stay, and closes it
|
||||
* when the lookup opens nothing: the panel shows this request's outcome.
|
||||
* `proceed()` is asked before a found image loads and before an empty
|
||||
* or failed lookup reports; false retires the request and leaves the
|
||||
* panel as it was (a photo that bills every load must not load for a
|
||||
* request its caller has given up).
|
||||
* under the screen centre (sky: nothing). Providers without
|
||||
* `nearestImage` are skipped. Options:
|
||||
* - `radiusM` widens the search where a provider can (a geocoded landmark
|
||||
* is rarely within 50 m of a street);
|
||||
* - `signal` retires the lookup: nothing opens after it fires;
|
||||
* - `armed: false` (the assistant's own request) ignores a link's armed
|
||||
* point and keeps it until a photo opens;
|
||||
* - `replace: true` keeps an open photo (and EXPAND) up while it looks and
|
||||
* closes it if nothing opens;
|
||||
* - `proceed()` is asked before a found photo loads or an empty lookup
|
||||
* reports; false retires the request and leaves the panel as it was.
|
||||
* Why nothing opened is in `street.nearestOutcome`: 'empty', 'sky' or
|
||||
* null (an error).
|
||||
*/
|
||||
async openNearest(
|
||||
point,
|
||||
@@ -737,9 +734,8 @@ export function createStreetLevelLayer({
|
||||
if (replace && state.street.open) closeViewer();
|
||||
};
|
||||
if (!point && aim === 'screen-centre' && armed) {
|
||||
// The button promises the centre of the view: the link's spot only
|
||||
// while the view still shows it, or when the view cannot be picked.
|
||||
// Sky refuses below, as any OPEN press does.
|
||||
// OPEN promises the view centre: the link's spot only while the view
|
||||
// still shows it, or when the view cannot be picked.
|
||||
const centre = armed.point ? screenCentreGround() : null;
|
||||
if (!armed.point) radiusM ??= armed.radiusM;
|
||||
else if (
|
||||
@@ -777,11 +773,9 @@ export function createStreetLevelLayer({
|
||||
callerSignal?.addEventListener('abort', onCallerAbort, { once: true });
|
||||
const retired = () => {
|
||||
callerSignal?.removeEventListener('abort', onCallerAbort);
|
||||
// Only the lookup that still owns the panel may touch it: a newer one
|
||||
// has its own spinner and error.
|
||||
// A newer lookup owns the panel, its spinner and its error.
|
||||
if (nearestLookup !== lookup) return false;
|
||||
nearestLookup = null;
|
||||
// The caller moved on: the panel shows nothing of this lookup.
|
||||
if (state.street.loading) {
|
||||
state.street.loading = false;
|
||||
notify();
|
||||
@@ -822,8 +816,7 @@ export function createStreetLevelLayer({
|
||||
if (proceed && proceed() !== true) return retired();
|
||||
nearestLookup = null;
|
||||
callerSignal?.removeEventListener('abort', onCallerAbort);
|
||||
// The photo asked for stays on screen: a sequence playing in the
|
||||
// photo it replaces stops.
|
||||
// A sequence playing in the replaced photo would step past this one.
|
||||
if (replace && state.street.open) parts.viewerHost.stopPlayback();
|
||||
// The caller's signal still counts while the viewer mounts and loads.
|
||||
return openImage(entry.def.id, imageId, {
|
||||
@@ -834,8 +827,7 @@ export function createStreetLevelLayer({
|
||||
callerSignal?.removeEventListener('abort', onCallerAbort);
|
||||
// Replaced while it looked: the panel is the newer lookup's.
|
||||
if (nearestLookup !== lookup) return false;
|
||||
// Given up by its caller while it looked: the open photo stays, and
|
||||
// the panel reports nothing of this lookup.
|
||||
// Given up by its caller: the panel stays as it was.
|
||||
if (proceed && proceed() !== true) return retired();
|
||||
nearestLookup = null;
|
||||
closeReplaced();
|
||||
@@ -867,8 +859,7 @@ export function createStreetLevelLayer({
|
||||
closeViewer,
|
||||
/**
|
||||
* Keep the open photo up while a request that replaces it switches the
|
||||
* source (the viewer and EXPAND are replaced, not closed). The returned
|
||||
* release closes it if its source is still off by then.
|
||||
* source, so EXPAND stays. Release closes it if its source is still off.
|
||||
*/
|
||||
holdViewer() {
|
||||
viewerHolds += 1;
|
||||
@@ -883,10 +874,9 @@ export function createStreetLevelLayer({
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Prepare a nearest lookup for the next OPEN press without running it: a
|
||||
* link to a source that bills every load stops here. The press opens at
|
||||
* this point with this radius; any other lookup, open or close, the
|
||||
* source switched off, or its map leaving clears it.
|
||||
* Arm a nearest lookup for the next OPEN press without running it (a link
|
||||
* to a source that bills every load). Any other lookup, open or close, the
|
||||
* source switched off or its map leaving clears it.
|
||||
*/
|
||||
armNearest(point, { providerIds = null, radiusM = null } = {}) {
|
||||
state.street.armed = {
|
||||
|
||||
@@ -75,17 +75,14 @@ export const SEQUENCE_IMAGE_FIELDS =
|
||||
'id,captured_at,compass_angle,geometry,is_pano';
|
||||
|
||||
/**
|
||||
* Images asked for in a nearest-image search (show_street_level and links
|
||||
* open the photo nearest a point; the graph API caps the radius at 50 m).
|
||||
* The API returns the radius's images in no particular order and cuts them
|
||||
* at the limit first, so this asks for its most (100): the distance sort and
|
||||
* the imagery filter then choose among the spot's photos, not a few of them.
|
||||
* Images asked for in a nearest-image search: the API cuts at the limit
|
||||
* before any order, so this is its most, and the distance sort and the
|
||||
* imagery filter choose among all of the spot's photos.
|
||||
*/
|
||||
export const NEAREST_LIMIT = 100;
|
||||
/**
|
||||
* A nearest-image search that has not answered (headers and body) in this
|
||||
* long is given up: a link or a posted view waits on it, and so does every
|
||||
* view queued behind that one.
|
||||
* A nearest-image search not answered in full (body included) by then is
|
||||
* given up: a link or posted view, and every view queued behind it, waits.
|
||||
*/
|
||||
export const NEAREST_TIMEOUT_MS = 12_000;
|
||||
/** Fields a nearest-image search needs: where each is, and the filter's. */
|
||||
|
||||
@@ -316,11 +316,9 @@ export class StreetLevelControls {
|
||||
}
|
||||
|
||||
/**
|
||||
* Embed mode hides the right rail, panel and viewer with it: an open photo
|
||||
* moves to <body> as an overlay on the globe (`sl-viewer-wrap-embed`, see
|
||||
* embed.css) and returns to its place in the panel when it closes. The
|
||||
* panel view keeps patching the wrap where it is: its siblings are static,
|
||||
* so Vue never inserts next to it.
|
||||
* Embed mode hides the right rail: an open photo moves to <body> as an
|
||||
* overlay on the globe (`sl-viewer-wrap-embed`, embed.css) and goes back
|
||||
* when it closes. Vue keeps patching the wrap there: its siblings are static.
|
||||
*/
|
||||
_syncEmbedOverlay(open) {
|
||||
const wrap = this._elements.viewerWrap;
|
||||
@@ -404,8 +402,6 @@ export class StreetLevelControls {
|
||||
if (!isEmbedPage()) this.actions.revealPanel?.();
|
||||
}
|
||||
this._wasOpen = open;
|
||||
// Embed mode hides the rail the panel sits in: an open photo is shown over
|
||||
// the globe instead, and goes back into the panel when it closes.
|
||||
this._syncEmbedOverlay(open);
|
||||
}
|
||||
|
||||
|
||||
+12
-21
@@ -3819,9 +3819,8 @@ function streetLevelPanelHidden() {
|
||||
* (links) stops short of a billed load: the panel is armed for OPEN.
|
||||
*/
|
||||
export async function showStreetLevel(args, context) {
|
||||
// Every await can hand the request's moment to someone else: a newer turn,
|
||||
// a navigation or gesture that takes the camera, or a mode that hides the
|
||||
// panel. Each stage after the place is settled checks again.
|
||||
// After any await a newer turn, a navigation, a globe gesture or a mode
|
||||
// that hides the panel may have taken over: each later stage checks again.
|
||||
const owner = watchCameraOwner(context.viewer, context.styleManager);
|
||||
// A photo held up while the request switches its source is let go however
|
||||
// the request ends: replaced by then, or closed if its source stayed off.
|
||||
@@ -3912,8 +3911,7 @@ async function requestStreetLevel(
|
||||
const status = layerModule.providerStatus?.(provider) || null;
|
||||
providerName = status?.name || provider;
|
||||
|
||||
// The key first, on any map: a chip without a key explains it and switches
|
||||
// nothing, and so does this.
|
||||
// The key first: without one nothing changes, as with a chip.
|
||||
if (status && (status.keyRequired === true || status.configured === false))
|
||||
return fail('key', status.error || `${providerName} needs its key`, {
|
||||
keyRejected: status.keyRejected === true,
|
||||
@@ -3998,9 +3996,8 @@ async function requestStreetLevel(
|
||||
point = { lat: location.latitude, lon: location.longitude };
|
||||
}
|
||||
|
||||
// Cockpit, clean view, recording and scene playback hide the panel the
|
||||
// photo opens in, and may have started during the flight.
|
||||
// The camera is the request's from where its own flight landed.
|
||||
// A mode that hides the panel may have started during the flight. The
|
||||
// camera is the request's from where its flight landed.
|
||||
if (location) owner.claim();
|
||||
const arrived = interrupted('view');
|
||||
if (arrived) return arrived;
|
||||
@@ -4076,13 +4073,11 @@ async function requestStreetLevel(
|
||||
location,
|
||||
});
|
||||
|
||||
// A billed source never loads from a link without a click: everything is
|
||||
// ready and OPEN is one press away at the view centre.
|
||||
// A link never loads a billed photo by itself: it arms OPEN instead.
|
||||
if (args.autoOpen === false && status?.billed === true) {
|
||||
// A photo of another place must not stay up beside the armed request.
|
||||
if (layerModule.getUIState?.()?.street?.open === true)
|
||||
layerModule.closeViewer?.();
|
||||
// The next OPEN press loads exactly what the link asked for.
|
||||
layerModule.armNearest?.(point, {
|
||||
providerIds: [provider],
|
||||
...(snapshot.groundClick === true
|
||||
@@ -4101,13 +4096,10 @@ async function requestStreetLevel(
|
||||
};
|
||||
}
|
||||
|
||||
// A source with no coverage to click (Street View) is searched wider: a
|
||||
// geocoded landmark is rarely within 50 m of a street. A newer turn
|
||||
// retires the lookup: nothing opens after the user moved on. A photo of
|
||||
// another place stays up while it looks (the viewer, EXPAND included, is
|
||||
// replaced, not closed) and closes if this request opens nothing: the
|
||||
// panel shows this request's outcome. Once an image is found it loads
|
||||
// only if the camera and the panel are still the request's.
|
||||
// Street View has no coverage to click, so it searches wider: a geocoded
|
||||
// landmark is rarely within 50 m of a street. An open photo stays up while
|
||||
// this looks and closes if nothing opens; a found photo loads only while
|
||||
// the camera and the panel are still the request's.
|
||||
reportProgress('imagery', label);
|
||||
const opened = await layerModule.openNearest(point, {
|
||||
providerIds: [provider],
|
||||
@@ -4123,9 +4115,8 @@ async function requestStreetLevel(
|
||||
: {}),
|
||||
});
|
||||
const street = layerModule.getUIState?.()?.street || {};
|
||||
// A cancelled request opens nothing (the lookup and the viewer both honour
|
||||
// the turn's signal). A photo that opened after the camera moved on, or
|
||||
// into a panel hidden meanwhile, is closed again: nobody asked to see it.
|
||||
// A photo that opened after the camera moved on, or into a panel hidden
|
||||
// meanwhile, is closed again.
|
||||
const late = interrupted('imagery');
|
||||
if (late) {
|
||||
if (opened === true) layerModule.closeViewer?.();
|
||||
|
||||
Reference in new issue
Block a user