Skip to content

Give map taps to the pin they landed on - #69

Merged
dfalling merged 1 commit into
mainfrom
fix-map-pin-hitboxes
Jul 31, 2026
Merged

Give map taps to the pin they landed on#69
dfalling merged 1 commit into
mainfrom
fix-map-pin-hitboxes

Conversation

@dfalling

Copy link
Copy Markdown
Owner

Summary

Tapping map pins was unreliable in two ways: a pin roughly a pin's width away would take the tap, and so would a pin buried underneath the one being aimed at.

Both came from how the press was resolved. MapLibre reports a press on the pin layer by handing over every feature rendered within a 44pt box around the touch (MLRNPressableSource.DEFAULT_HITBOX), and a pin's queryable area is its whole image — shadow padding included, ~67pt — so a tap near two pins routinely comes back with both, in an order the library doesn't define. We took features[0].

There was also no front pin to prefer instead: symbol-sort-key was 0 for every unselected pin, so which of two overlapping pins drew on top came down to the order their features happened to arrive in the source data.

Changes

  • Stack pins deliberatelysymbol-sort-key now comes from each pin's latitude, so southern pins draw over the ones behind them as on any map, with the selected pin above the lot.
  • New src/map/pinHitTest.ts — measures a tap against the pin's real outline. The drawn pin is exactly the convex hull of a circle and its tip (the three rounded corners share the square's centre, and the two sides at the tip are tangents to it), so containment is exact geometry rather than a bounding box. The pin whose outline the touch is inside wins; where two overlap, the one drawn on top; otherwise the nearest.
  • handlePinPress projects the candidates through mapRef.project and asks that module. A press with a single candidate is taken as-is with no round trip, so an isolated pin stays exactly as forgiving to hit as before.

A sort key can't depend on the camera, so with the map rotated far enough the latitude stacking reads upside down; the hit test uses the same key, so it always agrees with what's drawn.

Testing

  • 13 new unit tests covering neighbouring pins, stacked pins, the narrow tip, selected pins being larger, and duplicate/non-pin features. Full suite passes (41 tests), tsc and biome clean.
  • Not verified on a device: the debug build points at http://10.0.2.2:4000, so with no backend running there are no pins to tap.

MapLibre reports a press on the pin layer by handing over every feature
rendered within a 44pt box around the touch, and a pin's queryable area
is its whole image, shadow padding included — so a tap near two pins
comes back with both, in an order the library doesn't define. Taking the
first of them gave the tap to an arbitrary pin: often a neighbour a pin's
width away.

Nor was there a pin "on top" to prefer instead: every unselected pin had
the same sort key, leaving the stacking of two overlapping pins to the
order their features happened to arrive in. A pin you couldn't see could
take the tap and nothing was wrong.

So stack the pins deliberately, by latitude, and measure the candidates
against where they are really drawn: the pin whose outline the touch is
inside wins, the front one where two overlap, the nearest otherwise. A
touch with only one candidate is still taken as-is, so an isolated pin
stays as forgiving to hit as MapLibre's hitbox makes it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dfalling
dfalling merged commit 36d99dc into main Jul 31, 2026
2 checks passed
@dfalling
dfalling deleted the fix-map-pin-hitboxes branch July 31, 2026 17:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant