Skip to content

feat(ui): image map current-image marker, focal-point zoom, auto-recenter - #40

Open
lstein wants to merge 1 commit into
feat/image-map-06-floatingfrom
feat/image-map-07-marker-zoom
Open

feat(ui): image map current-image marker, focal-point zoom, auto-recenter#40
lstein wants to merge 1 commit into
feat/image-map-06-floatingfrom
feat/image-map-07-marker-zoom

Conversation

@lstein

@lstein lstein commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

PR 7 of the Image Map stack — PhotoMapAI's interaction core:

  • The gold current-image target tracks the gallery selection live: any selection restyles just the one-point marker trace, and when the marker drifts within 10% of a view edge the map recenters on it, preserving zoom width. Map-originated selections never recenter under the cursor (time-limited suppression stamps, so stale entries cannot suppress future recenters). The marker uses hoverinfo: 'skip' so it never shadows the point beneath it for clicks/hovers.
  • Custom focal-point wheel zoom + two-finger pinch (exp gain, ctrl+wheel = trackpad pinch), replacing plotly's scrollZoom (Safari issues). Coincident-touch pinch starts and zero/negative zoom factors are guarded; pinch-end synthetic clicks are suppressed including held-still pinches.
  • View preservation done right: each data refresh feeds the current axis ranges back into Plotly.react — verified against the bundled plotly source that uirevision alone does not preserve ranges set via the public relayout API. Percentile ranges (1st–99th) seed only the very first render.
  • All plotly restyle/relayout calls swallow rejections (WebGL-failure environments already surface an error through the store).

An adversarial review of this diff was run (it verified plotly semantics against the bundled source); all five findings — the false uirevision contract, the suppression-ref protocol breaks, pinch collapse, held-pinch click leak, and unhandled rejections — are fixed above, with tightened exact-value tests for the zoom math.

Testing

Pure viewport math fully unit-tested (percentiles incl. outliers/degenerate inputs, focal-invariant zoom + inverse property, exact wheel gains, non-positive factor clamp, width-preserving recenter, pad band). 907-test suite + lint + build pass at the stack top.

🤖 Generated with Claude Code

@lstein
lstein requested a review from blessedcoolant as a code owner August 2, 2026 21:49
@github-actions github-actions Bot added the python label Aug 2, 2026
@lstein
lstein marked this pull request as draft August 2, 2026 22:23
@lstein
lstein force-pushed the feat/image-map-07-marker-zoom branch from e01c3ee to 3a5662d Compare August 2, 2026 22:38
@lstein
lstein force-pushed the feat/image-map-06-floating branch from 035de15 to d36b46d Compare August 3, 2026 01:38
@lstein
lstein force-pushed the feat/image-map-07-marker-zoom branch from 3a5662d to 84be196 Compare August 3, 2026 01:38
@lstein
lstein force-pushed the feat/image-map-06-floating branch from d36b46d to 0a64ade Compare August 3, 2026 02:26
@lstein
lstein force-pushed the feat/image-map-07-marker-zoom branch 2 times, most recently from 7960b81 to f15c9c5 Compare August 3, 2026 18:19
@lstein
lstein marked this pull request as ready for review August 3, 2026 18:28
@lstein
lstein force-pushed the feat/image-map-07-marker-zoom branch from f15c9c5 to e55f4db Compare August 4, 2026 01:43
@lstein
lstein force-pushed the feat/image-map-06-floating branch 2 times, most recently from a58e9c7 to d7e56a7 Compare August 4, 2026 05:37
@lstein
lstein force-pushed the feat/image-map-07-marker-zoom branch from e55f4db to 3545b1f Compare August 4, 2026 05:37
@lstein
lstein force-pushed the feat/image-map-06-floating branch from d7e56a7 to 925649a Compare August 4, 2026 14:58
@lstein
lstein force-pushed the feat/image-map-07-marker-zoom branch 2 times, most recently from 343998e to cc30d46 Compare August 4, 2026 22:32
@lstein
lstein force-pushed the feat/image-map-06-floating branch 2 times, most recently from 08aa934 to ef19bf0 Compare August 5, 2026 00:31
@lstein
lstein force-pushed the feat/image-map-07-marker-zoom branch from cc30d46 to 16273bb Compare August 5, 2026 00:31
@lstein
lstein force-pushed the feat/image-map-06-floating branch from ef19bf0 to 8666f99 Compare August 5, 2026 00:38
@lstein
lstein force-pushed the feat/image-map-07-marker-zoom branch from 16273bb to aae9670 Compare August 5, 2026 00:38
@lstein
lstein force-pushed the feat/image-map-06-floating branch from 8666f99 to dc89f69 Compare August 5, 2026 01:18
@lstein
lstein force-pushed the feat/image-map-07-marker-zoom branch from aae9670 to 640ce5a Compare August 5, 2026 01:18
…nter

Ports PhotoMapAI's interaction core to the Image Map widget:

- The gold "Current Image" target now tracks the gallery selection live:
  selecting anywhere (gallery grid, arrows, the map itself) restyles just
  the single-point marker trace, and when the marker drifts within 10% of
  a viewport edge the view recenters on it, preserving the zoom width.
  Selections that originate from a map click never recenter the map under
  the user's cursor.
- Custom focal-point wheel zoom and two-finger pinch (exp gain, ctrl+wheel
  treated as trackpad pinch), replacing plotly's scrollZoom for its
  long-standing Safari issues. Pinch-end synthetic clicks are suppressed.
- Initial view fits the 1st-99th percentile of coordinates so a few
  outliers cannot dwarf the map; `uirevision` preserves the user's pan and
  zoom across data refreshes.

All viewport math (percentile ranges, focal-invariant zoom, width-
preserving recenter) lives in a pure module with unit tests; the plotly
host only glues events to it.

Amended during the rebase onto the re-architected webv2:

- The current-selection accessor now comes from the gallery feature's
  public interface: `getSelectedGalleryImageFromValues` is imported from
  `@features/gallery/contracts` (the same helper PreviewWidgetView uses)
  instead of the old `@workbench/image-actions/selectedImage`. It resolves
  main's mixed image/video `GalleryItem` selection and already returns
  images only, so a video selection simply clears the gold marker.
- `useWidgetValuesSelector('gallery', ...)` from @workbench/
  WorkbenchContext is unchanged and keeps feeding the selector; the
  map-click suppression handshake with useSelectMapImage still matches by
  image name, which survives the GalleryItem round-trip.
- performance/architecture-baseline.json reformatted (one array collapsed
  to a single line) to satisfy oxfmt; the drift came in with the earlier
  ported baselines. No baseline values changed and the build-time
  performance check passes without a recapture — all new code lands in
  the lazy plotly widget chunk.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@lstein
lstein force-pushed the feat/image-map-06-floating branch from dc89f69 to b3136de Compare August 5, 2026 01:21
@lstein
lstein force-pushed the feat/image-map-07-marker-zoom branch from 640ce5a to d36dbbb Compare August 5, 2026 01:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant