fix(street-level): KartaView round-2 follow-ups — context loss, size cap, slow lookups

From the second IC8 pass (launch ready; P3s closed here):
- A lost WebGL context is redrawn on a new canvas (the old one only gives
  back its lost context), through the core, and only if no newer photo is
  opening; verified live with WEBGL_lose_context, twice.
- The 16 MB answer cap counts bytes while reading: KartaView sends
  chunked answers with no Content-Length, so the header check never fired.
- A lookup gets 8 s, then 15 s once more: KartaView sometimes sits on a
  lookup for 11 s and answers the same one in 3 s.

Left as follow-ups: cancelling abandoned sequence pages; finding a page
by binary search on the index when thousands of photos are missing.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Said TurkseverandClaude Opus 5.5 committed 2026-10-13 21:03:13 +01:00
1 parent 0394a9b908
commit 97a1a667de
7 files changed
+158 -24

No files matched your search

@@ -83,6 +83,8 @@ export function createKartaViewViewer({
let drag = null;
let poseFrame = 0;
let removeListeners = [];
/** The document the viewer was built in (new canvases come from it). */
let documentOf = null;
/** The photo an open is fetching: ‹ › step on from it, not the old one. */
let openingId = null;
/** ‹ › chose this photo: keep the panorama's look direction for it. */
@@ -202,13 +204,35 @@ export function createKartaViewViewer({
} catch {
/* already gone */
}
if (showing === 'pano' && photo) {
// A lost canvas hands back its lost context: draw on a new element.
const fresh = makeCanvas(documentOf);
fresh.hidden = canvas.hidden;
canvas.replaceWith?.(fresh);
canvas = fresh;
// Show the photo again through the core, unless a newer one is opening.
if (showing === 'pano' && photo && openingId === null) {
const again = photo.id;
show(null);
adapter.open(again).catch(() => {});
keepViewFor = again;
openingId = again;
onStep(again);
}
}
/** The panorama canvas, wired for drag, pinch, wheel and context loss. */
function makeCanvas(doc) {
const element = doc.createElement('canvas');
element.className = 'sl-kv-pano';
element.hidden = true;
listen(element, 'pointerdown', onPointerDown);
listen(element, 'pointermove', onPointerMove);
listen(element, 'pointerup', onPointerUp);
listen(element, 'pointercancel', onPointerUp);
listen(element, 'wheel', onWheel, { passive: false });
listen(element, 'webglcontextlost', onContextLost);
return element;
}
/**
* Step along the sequence from the photo showing, or from the one on its
* way after an earlier press, and open it through the core.
@@ -346,6 +370,7 @@ export function createKartaViewViewer({
function build(host) {
const doc = host.ownerDocument;
documentOf = doc;
root = doc.createElement('div');
root.className = 'sl-kv-viewer';
root.tabIndex = 0;
@@ -359,9 +384,7 @@ export function createKartaViewViewer({
picture.alt = 'KartaView street-level photo';
picture.draggable = false;
picture.hidden = true;
canvas = doc.createElement('canvas');
canvas.className = 'sl-kv-pano';
canvas.hidden = true;
canvas = makeCanvas(doc);
const nav = (label, glyph, delta) => {
const button = doc.createElement('button');
button.type = 'button';
@@ -380,12 +403,6 @@ export function createKartaViewViewer({
nextButton = nav('Next photo in this sequence (→)', '›', 1);
root.append(picture, canvas, prevButton, nextButton);
host.append(root);
listen(canvas, 'pointerdown', onPointerDown);
listen(canvas, 'pointermove', onPointerMove);
listen(canvas, 'pointerup', onPointerUp);
listen(canvas, 'pointercancel', onPointerUp);
listen(canvas, 'wheel', onWheel, { passive: false });
listen(canvas, 'webglcontextlost', onContextLost);
listen(root, 'keydown', onKeyDown);
applyRenderMode();
}