mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
refactor(street-level): no sequence image cache; one pose listener
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
1db3290e0b
commit
09e2fd96a4
4 files changed
+11
-51
No files matched your search
@@ -11,9 +11,6 @@ import {
|
||||
|
||||
const SPRITE_ID = 'street-level:mapillary-cones';
|
||||
|
||||
/** How many recently viewed sequences keep their image list in memory. */
|
||||
const SEQUENCE_CACHE_SIZE = 40;
|
||||
|
||||
/** Normalize a graph image record into the shape the cones use. */
|
||||
function normalizeSequenceImage(record) {
|
||||
const coordinates = record?.geometry?.coordinates;
|
||||
@@ -115,14 +112,6 @@ export function createSequences({ state, source, parts }) {
|
||||
requestRender();
|
||||
}
|
||||
|
||||
function remember(sequenceId, images) {
|
||||
const { cache } = state.sequence;
|
||||
cache.delete(sequenceId);
|
||||
cache.set(sequenceId, images);
|
||||
while (cache.size > SEQUENCE_CACHE_SIZE)
|
||||
cache.delete(cache.keys().next().value);
|
||||
}
|
||||
|
||||
/** Select a sequence: highlight its line and load its image cones. */
|
||||
async function select(sequenceId) {
|
||||
if (!sequenceId || !state.viewer) return;
|
||||
@@ -135,16 +124,6 @@ export function createSequences({ state, source, parts }) {
|
||||
state.sequence.abort?.abort();
|
||||
state.sequence.selectedId = sequenceId;
|
||||
parts.coverage.highlight(sequenceId);
|
||||
const cached = state.sequence.cache.get(sequenceId);
|
||||
if (cached) {
|
||||
state.sequence.abort = null;
|
||||
state.sequence.loading = false;
|
||||
state.sequence.images = cached;
|
||||
renderCones(cached);
|
||||
state.sequence.error = null;
|
||||
notify();
|
||||
return;
|
||||
}
|
||||
// The previous sequence's cones must not stay clickable under the new
|
||||
// highlight while this one loads, nor after its load fails.
|
||||
clearCones();
|
||||
@@ -164,7 +143,6 @@ export function createSequences({ state, source, parts }) {
|
||||
.filter(Boolean)
|
||||
.sort((a, b) => a.capturedAt - b.capturedAt),
|
||||
);
|
||||
remember(sequenceId, images);
|
||||
state.sequence.images = images;
|
||||
renderCones(images);
|
||||
state.sequence.error = null;
|
||||
|
||||
@@ -67,7 +67,6 @@ function setup() {
|
||||
sequence: {
|
||||
selectedId: null,
|
||||
images: [],
|
||||
cache: new Map(),
|
||||
collection: cones(),
|
||||
loading: false,
|
||||
error: null,
|
||||
@@ -112,7 +111,7 @@ test('a failed sequence load leaves no stale cones and can be retried', async ()
|
||||
assert.equal(state.sequence.error, null, 'cleared once B loads');
|
||||
});
|
||||
|
||||
test('a late answer for a superseded sequence neither draws nor is cached', async () => {
|
||||
test('a late answer for a superseded sequence draws nothing', async () => {
|
||||
const { state, source, sequences, drawn } = setup();
|
||||
sequences.select('A');
|
||||
sequences.select('B');
|
||||
@@ -123,7 +122,6 @@ test('a late answer for a superseded sequence neither draws nor is cached', asyn
|
||||
await settle();
|
||||
assert.deepEqual(drawn(), ['B-0', 'B-1']);
|
||||
assert.equal(state.sequence.selectedId, 'B');
|
||||
assert.equal(state.sequence.cache.has('A'), false);
|
||||
assert.equal(state.sequence.loading, false);
|
||||
});
|
||||
|
||||
@@ -135,21 +133,6 @@ test('a second click on a loading sequence does not start another lookup', async
|
||||
assert.equal(source.calls[0].signal.aborted, false);
|
||||
});
|
||||
|
||||
test('a cached sequence is re-selected without a lookup', async () => {
|
||||
const { state, source, sequences, drawn } = setup();
|
||||
sequences.select('A');
|
||||
source.last('A').resolve(records('A'));
|
||||
await settle();
|
||||
sequences.select('B');
|
||||
source.last('B').resolve(records('B'));
|
||||
await settle();
|
||||
sequences.select('A');
|
||||
assert.equal(source.calls.length, 2, 'A came from the cache');
|
||||
assert.deepEqual(drawn(), ['A-0', 'A-1'], 'drawn at once');
|
||||
assert.equal(state.sequence.loading, false);
|
||||
assert.equal(state.sequence.selectedId, 'A');
|
||||
});
|
||||
|
||||
test('clearSelection cancels the lookup and drops the highlight', async () => {
|
||||
const { state, source, sequences, highlights, drawn } = setup();
|
||||
sequences.select('A');
|
||||
|
||||
@@ -27,7 +27,8 @@ export function createMapillaryViewer({ source, render } = {}) {
|
||||
let renderMode = 'letterbox';
|
||||
/** Metadata of the image on screen; pov/position events reuse it. */
|
||||
let current = null;
|
||||
const listeners = new Set();
|
||||
/** The pose listener (the viewer host); one at a time. */
|
||||
let poseListener = null;
|
||||
|
||||
function requestRender() {
|
||||
render?.governorRequestRender?.('mapillary-viewer');
|
||||
@@ -52,12 +53,10 @@ export function createMapillaryViewer({ source, render } = {}) {
|
||||
}
|
||||
|
||||
function emit(pose) {
|
||||
for (const listener of [...listeners]) {
|
||||
try {
|
||||
listener(pose);
|
||||
} catch {
|
||||
/* listener errors are the core's to log */
|
||||
}
|
||||
try {
|
||||
poseListener?.(pose);
|
||||
} catch {
|
||||
/* listener errors are the core's to log */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,8 +200,10 @@ export function createMapillaryViewer({ source, render } = {}) {
|
||||
},
|
||||
|
||||
onPose(listener) {
|
||||
listeners.add(listener);
|
||||
return () => listeners.delete(listener);
|
||||
poseListener = listener;
|
||||
return () => {
|
||||
if (poseListener === listener) poseListener = null;
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -71,8 +71,6 @@ export function createState({ services }) {
|
||||
sequence: {
|
||||
selectedId: null,
|
||||
images: [],
|
||||
/** Recent sequences' thinned images, by sequence id. */
|
||||
cache: new Map(),
|
||||
collection: null,
|
||||
loading: false,
|
||||
/** Why the selected sequence's images could not load, until it goes. */
|
||||
|
||||
Reference in new issue
Block a user