fix(street-level): Panoramax UX QA — connection budget, coverage to 60 km, Esc, attribution

From a UX QA round in the browser against the live API:
- A line click could time out while coverage loaded: the meta-catalogue
  speaks HTTP/1.1 only (six connections), and six tiles plus four
  searches queued the lookup behind megabyte tiles. Tiles now take
  three connections and searches two; a search that timed out is asked
  once more.
- Between 30 and ~100 km Paris read as empty: the density grid is ~10 km
  a cell. Lines now draw to 60 km (z10), as Mapillary's do; above, dots
  grow with the pictures they stand for.
- Esc in the docked viewer collapsed the whole panel instead of clearing
  the sequence the panel says it clears (shared photo viewer: KartaView
  too). The viewer now offers Esc to the provider first; expanded, the
  dialog keeps it.
- A picture whose producer is an email address is credited to the
  instance holding it (its `via` host), so Licence Ouverte pictures name
  their source.
- Empty states say why: "no Panoramax photos here match the filters"
  when the filter hid every line, and nothing to zoom into over empty
  sea. Wording follows KartaView's ("photos", "click a line for its
  nearest photo").

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Said TurkseverandClaude Opus 5.5 committed 2026-10-14 14:37:45 +01:00
1 parent bce3044e0c
commit 5526666894
14 files changed
+317 -45

No files matched your search

+3 -1
View File
@@ -95,6 +95,7 @@ export function meshBoxInRange(box, centre) {
* @param {LineCoverageTuning} options.tuning
* @param {{keyRejected?: string, rateLimited: string, tooHigh?: string}} options.messages
* @param {(sequence: object, filter: object) => boolean} [options.passes] Whether the imagery filter keeps a line or point.
* @param {(point: object) => number} [options.overviewPointSize] An overview point's size in pixels (default `tuning.overviewPointPx`).
*/
export function createLineCoverage({
state,
@@ -106,6 +107,7 @@ export function createLineCoverage({
tuning,
messages,
passes = passesImageryFilter,
overviewPointSize = null,
}) {
const { render } = state.services;
const perTileSequenceCap = Math.floor(tuning.maxSequences / tuning.maxTiles);
@@ -427,7 +429,7 @@ export function createLineCoverage({
collection.add({
position: Cesium.Cartesian3.fromDegrees(point.lon, point.lat),
color: tint,
pixelSize: tuning.overviewPointPx,
pixelSize: overviewPointSize?.(point) ?? tuning.overviewPointPx,
// Google 3D terrain and clouds must not hide the near side's dots;
// the horizon cull hides the far side's, which this lets through.
disableDepthTestDistance: Number.POSITIVE_INFINITY,