mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
refactor(street-level): trim QA, tests, styles and docs
The browser gate is one pass over the remaining flows: rail strip and expand, coverage with fixtures, the ON/OFF pill, 360° and SINCE filters, KEY REJECTED, nearest photo with caption, × close, phone fit, keyless KEY REQUIRED on a second page and no page errors. Panel controls are pressed through the DOM; pick-point search, line/cone clicks, the framing-cancel, reload/share and status-route probes, the second viewport and pointer-settling retries are gone (unit tests cover them). Tests that pinned constants, copy, CSS or source text, or repeated another test, are removed or merged. CSS loses an unused variable and duplicate rules. Docs describe the slimmed feature; unused exports and the layer's dead setCoverageFilter/refreshCoverage surface are removed. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
b5a78826f8
commit
ad58a0bdc4
23 files changed
+534
-1693
No files matched your search
@@ -318,8 +318,6 @@ export function createStreetLevelLayer({
|
||||
attachViewerHost(element) {
|
||||
parts.viewerHost.attach(element);
|
||||
},
|
||||
/** Imagery filter for coverage, cones and nearest-image lookups. */
|
||||
setCoverageFilter,
|
||||
openImage,
|
||||
/** Open the nearest image around a point (default: the view centre). */
|
||||
async openNearest(point) {
|
||||
@@ -366,7 +364,6 @@ export function createStreetLevelLayer({
|
||||
resizeViewer: () => parts.viewerHost.resize(),
|
||||
selectSequence: (sequenceId) => parts.sequences.select(sequenceId),
|
||||
clearSequence: () => parts.sequences.clearSelection(),
|
||||
refreshCoverage: () => parts.coverage.refresh(),
|
||||
};
|
||||
return layer;
|
||||
}
|
||||
@@ -143,18 +143,6 @@ function slowLookups() {
|
||||
return { lookups, source: fakeMapillarySource({ nearestImages }) };
|
||||
}
|
||||
|
||||
test('the layer is Mapillary under the codec keys it has always had', () => {
|
||||
const layer = createStreetLevelLayer({ source: fakeMapillarySource() });
|
||||
assert.equal(layer.id, 'street-level');
|
||||
assert.equal(layer.requiresKeyId, 'mapillary');
|
||||
assert.deepEqual(layer.getParams(), {
|
||||
mapillary: true,
|
||||
pano: 'all',
|
||||
sinceDays: 0,
|
||||
});
|
||||
assert.throws(() => createStreetLevelLayer({ source: {} }), /source/);
|
||||
});
|
||||
|
||||
test('the CC BY-SA credit shows while Mapillary is on and goes with it', async (t) => {
|
||||
const { layer, viewer } = await startLayer(t);
|
||||
const shown = () => viewer.credits.map((credit) => credit.html);
|
||||
@@ -284,7 +272,7 @@ test('a sequence error is withdrawn with the sequence, never the viewer’s own'
|
||||
assert.match(layer.getUIState().street.error, /Open the Street Level panel/);
|
||||
});
|
||||
|
||||
test('closing the photo stops the globe flying to it', async (t) => {
|
||||
test('closing the photo, switching the layer off or destroying it stops the framing flight', async (t) => {
|
||||
const { layer, viewer } = await startLayer(t, {
|
||||
photoViewer: posingViewer(),
|
||||
});
|
||||
@@ -292,35 +280,16 @@ test('closing the photo stops the globe flying to it', async (t) => {
|
||||
assert.equal(await layer.openImage('img1'), true);
|
||||
assert.equal(viewer.flights.started, 1, 'the photo is framed');
|
||||
layer.closeViewer();
|
||||
assert.equal(viewer.flights.cancelled, 1);
|
||||
});
|
||||
assert.equal(viewer.flights.cancelled, 1, 'closed');
|
||||
|
||||
test('switching the layer off or destroying it stops the framing flight', async (t) => {
|
||||
const { layer, viewer } = await startLayer(t, {
|
||||
photoViewer: posingViewer(),
|
||||
});
|
||||
layer.attachViewerHost({});
|
||||
await layer.openImage('img1');
|
||||
await layer.openImage('img2');
|
||||
layer.disable();
|
||||
assert.equal(viewer.flights.cancelled, 1, 'layer off');
|
||||
assert.equal(viewer.flights.cancelled, 2, 'layer off');
|
||||
|
||||
layer.enable(viewer);
|
||||
await layer.openImage('img2');
|
||||
await layer.openImage('img3');
|
||||
layer.destroy();
|
||||
assert.equal(viewer.flights.cancelled, 2, 'destroyed');
|
||||
});
|
||||
|
||||
test('closing the photo leaves a newer navigation flight alone', async (t) => {
|
||||
const { layer, viewer } = await startLayer(t, {
|
||||
photoViewer: posingViewer(),
|
||||
});
|
||||
layer.attachViewerHost({});
|
||||
await layer.openImage('img1');
|
||||
assert.equal(viewer.flights.started, 1, 'the photo is being framed');
|
||||
// A search result flies the globe elsewhere before the framing lands.
|
||||
viewer.camera.flyToBoundingSphere(null, {});
|
||||
layer.closeViewer();
|
||||
assert.equal(viewer.flights.cancelled, 0, 'the search flight keeps going');
|
||||
assert.equal(viewer.flights.cancelled, 3, 'destroyed');
|
||||
});
|
||||
|
||||
test('an older nearest lookup that answers late cannot replace a newer one', async (t) => {
|
||||
@@ -383,7 +352,13 @@ test('closing the viewer or switching the layer off retires a nearest lookup', a
|
||||
});
|
||||
|
||||
test('setParams takes "any date" (0 days) and the switch over the current values (share-link defaults)', async (t) => {
|
||||
assert.throws(() => createStreetLevelLayer({ source: {} }), /source/);
|
||||
const { layer } = await startLayer(t);
|
||||
assert.deepEqual(layer.getParams(), {
|
||||
mapillary: true,
|
||||
pano: 'all',
|
||||
sinceDays: 0,
|
||||
});
|
||||
layer.setParams({ pano: 'flat', sinceDays: 365 });
|
||||
assert.equal(layer.getParams().sinceDays, 365);
|
||||
layer.setParams({ sinceDays: 0 });
|
||||
|
||||
@@ -57,7 +57,7 @@ export function sequenceIdFromPick(pickId) {
|
||||
/** Hint above the street-zoom ceiling, where no coverage is drawn. */
|
||||
export const ZOOM_IN_HINT = 'Zoom in to see street-level coverage';
|
||||
/** Hint when no ground is in view within range (looking at the sky). */
|
||||
export const NO_GROUND_HINT =
|
||||
const NO_GROUND_HINT =
|
||||
'Point the camera at the ground for street-level coverage';
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,7 @@ import { PbfWriter } from 'pbf';
|
||||
const zigzag = (value) => (value << 1) ^ (value >> 31);
|
||||
|
||||
/** Tile-local [x, y] (0..extent) of a lon/lat inside tile (x, y, z). */
|
||||
export function lonLatToTileLocal([lon, lat], { x, y, z }, extent = 4096) {
|
||||
function lonLatToTileLocal([lon, lat], { x, y, z }, extent = 4096) {
|
||||
const n = 2 ** z;
|
||||
const rad = (lat * Math.PI) / 180;
|
||||
const tx = ((lon + 180) / 360) * n;
|
||||
|
||||
@@ -19,7 +19,7 @@ function linePart(points) {
|
||||
|
||||
/**
|
||||
* A minimal mly1_public-shaped tile: one sequence line, plus one point in the
|
||||
* low-zoom `overview` layer the layer never draws.
|
||||
* z14 `image` layer the decoder skips.
|
||||
*/
|
||||
function sampleTile({ geometry = null } = {}) {
|
||||
const writer = new PbfWriter();
|
||||
@@ -73,7 +73,7 @@ function sampleTile({ geometry = null } = {}) {
|
||||
3,
|
||||
(_, layer) => {
|
||||
layer.writeVarintField(15, 2);
|
||||
layer.writeStringField(1, 'overview');
|
||||
layer.writeStringField(1, 'image');
|
||||
layer.writeVarintField(5, 4096);
|
||||
layer.writeStringField(3, 'is_pano');
|
||||
layer.writeMessage(
|
||||
@@ -97,7 +97,7 @@ function sampleTile({ geometry = null } = {}) {
|
||||
return new Uint8Array(writer.finish());
|
||||
}
|
||||
|
||||
test('sequences decode into lon/lat records; overview points are ignored', () => {
|
||||
test('sequences decode into lon/lat records; image points are skipped', () => {
|
||||
const decoded = decodeCoverageTile(sampleTile(), { x: 0, y: 0, z: 1 });
|
||||
assert.equal(decoded.sequences.length, 1);
|
||||
const [sequence] = decoded.sequences;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { nearestImageId } from './nearest.js';
|
||||
import { COLORS, mapillaryImageUrl } from './policy.js';
|
||||
import { mapillaryImageUrl } from './policy.js';
|
||||
import { sequenceIdFromPick } from './coverage.js';
|
||||
import { thinImages } from './sequences.js';
|
||||
import { resolveFilter } from '../../filter.js';
|
||||
@@ -27,8 +27,7 @@ const at = (id, lon, lat) => ({
|
||||
geometry: { type: 'Point', coordinates: [lon, lat] },
|
||||
});
|
||||
|
||||
test('Mapillary draws in its green; image deep links match the mapillary.com share format', () => {
|
||||
assert.equal(COLORS.coverage, '#05cb63');
|
||||
test('image deep links match the mapillary.com share format', () => {
|
||||
assert.equal(
|
||||
mapillaryImageUrl(1814275685699406),
|
||||
'https://www.mapillary.com/app/?pKey=1814275685699406&focus=photo',
|
||||
|
||||
@@ -15,7 +15,7 @@ const SPRITE_ID = 'street-level:mapillary-cones';
|
||||
const SEQUENCE_CACHE_SIZE = 40;
|
||||
|
||||
/** Normalize a graph image record into the shape the cones use. */
|
||||
export function normalizeSequenceImage(record) {
|
||||
function normalizeSequenceImage(record) {
|
||||
const coordinates = record?.geometry?.coordinates;
|
||||
if (!Array.isArray(coordinates) || coordinates.length < 2) return null;
|
||||
return {
|
||||
|
||||
@@ -104,12 +104,6 @@ test('graph API errors carry the upstream message and status', async () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('the source exposes only imagery lookups', () => {
|
||||
const source = createMapillarySource({ token: 'MLY|1|abc' });
|
||||
for (const gone of ['queryFeatures', 'plan', 'geocode', 'spriteUrl'])
|
||||
assert.equal(source[gone], undefined, gone);
|
||||
});
|
||||
|
||||
test('a rejected key and a rate limit are told apart from other tile errors', async () => {
|
||||
const rejectedSource = createMapillarySource({
|
||||
token: 'MLY|1|abc',
|
||||
|
||||
@@ -41,13 +41,6 @@ test('normalizeBbox orders and clamps coordinates', () => {
|
||||
assert.equal(normalizeBbox([1, 2, Number.NaN, 3]), null);
|
||||
});
|
||||
|
||||
test('city-scale boxes span many z14 tiles', () => {
|
||||
const sacramento = [-121.56, 38.44, -121.36, 38.69];
|
||||
assert.equal(tilesForBbox(sacramento, 14).total, 160);
|
||||
const detroit = [-83.29, 42.25, -82.91, 42.45];
|
||||
assert.equal(tilesForBbox(detroit, 14).total, 234);
|
||||
});
|
||||
|
||||
test('tilesForBbox orders from the centre outwards and honours the cap', () => {
|
||||
const result = tilesForBbox([-121.56, 38.44, -121.36, 38.69], 14, {
|
||||
limit: 5,
|
||||
|
||||
@@ -154,7 +154,7 @@ export function cameraNadir(viewer) {
|
||||
* Horizon occluder depth below WGS84 (m): ground can lie below the ellipsoid
|
||||
* (NYC −22 m), and an occluder at 0 m would hide the cones around it.
|
||||
*/
|
||||
export const HORIZON_CULL_DEPTH_M = 1000;
|
||||
const HORIZON_CULL_DEPTH_M = 1000;
|
||||
const HORIZON_CULL_ELLIPSOID = new Cesium.Ellipsoid(
|
||||
Cesium.Ellipsoid.WGS84.radii.x - HORIZON_CULL_DEPTH_M,
|
||||
Cesium.Ellipsoid.WGS84.radii.y - HORIZON_CULL_DEPTH_M,
|
||||
|
||||
@@ -189,24 +189,6 @@ function deferred() {
|
||||
return { promise, resolve };
|
||||
}
|
||||
|
||||
test('switching the layer off and on during a cold first open keeps the shared viewer', async () => {
|
||||
const gate = deferred();
|
||||
const adapter = fakeAdapter({ gate });
|
||||
const { state, host } = harness(adapter);
|
||||
const first = host.open('a'); // the library is still loading
|
||||
host.unmount(); // layer off …
|
||||
const second = host.open('b'); // … on again, and a new click
|
||||
gate.resolve();
|
||||
await Promise.all([first, second]);
|
||||
assert.equal(adapter.calls.unmount, 1, 'only the layer going off');
|
||||
assert.equal(adapter.calls.listeners, 1);
|
||||
assert.equal(state.street.error, null);
|
||||
assert.equal(state.street.imageId, 'b');
|
||||
await host.open('c');
|
||||
assert.equal(state.street.error, null, 'later opens are not stuck');
|
||||
assert.equal(state.street.imageId, 'c');
|
||||
});
|
||||
|
||||
const settle = () => new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
test('every pose the viewer reports moves the marker; only the open frames the camera', async () => {
|
||||
@@ -393,15 +375,6 @@ test('a Mapillary viewer unmounted mid-download is never built; the next mount b
|
||||
assert.equal(viewers.live, 0, 'nothing left holding a WebGL context');
|
||||
});
|
||||
|
||||
test('the Mapillary viewer leaves resizing to the panel, so a hidden one never asks for z=NaN', async () => {
|
||||
const { gate, viewers } = fakeLibrary();
|
||||
gate.resolve();
|
||||
const adapter = createMapillaryViewer({ source: { token: 't' } });
|
||||
await adapter.mount({});
|
||||
assert.equal(viewers.instances[0].options.trackResize, false);
|
||||
adapter.unmount();
|
||||
});
|
||||
|
||||
test('closing the photo stops sequence playback in the hidden viewer', async () => {
|
||||
const { gate, viewers } = fakeLibrary();
|
||||
gate.resolve();
|
||||
@@ -415,18 +388,6 @@ test('closing the photo stops sequence playback in the hidden viewer', async ()
|
||||
assert.equal(viewers.live, 1, 'the viewer itself stays warm');
|
||||
});
|
||||
|
||||
test('closing the photo or switching the layer off stops its framing flight', async () => {
|
||||
const adapter = fakeAdapter();
|
||||
const { framing, host } = harness(adapter);
|
||||
await host.open('a');
|
||||
assert.equal(framing.started, 1, 'the open framed the photo');
|
||||
host.close();
|
||||
assert.equal(framing.cancelled, 1, 'closed: the globe stops flying to it');
|
||||
await host.open('b');
|
||||
host.unmount();
|
||||
assert.equal(framing.cancelled, 2, 'layer off: likewise');
|
||||
});
|
||||
|
||||
/** The real Mapillary adapter, mounted on a ready library, and its poses. */
|
||||
async function mountedMapillary() {
|
||||
const library = fakeLibrary();
|
||||
|
||||
Reference in new issue
Block a user