feat(map): declutter overlapping contact markers#572
feat(map): declutter overlapping contact markers#572torlando-tech merged 8 commits intotorlando-tech:mainfrom
Conversation
Greptile SummaryThis PR implements a sophisticated marker decluttering system for the map screen. When multiple contacts share nearby GPS positions, their markers overlap and become unreadable. The solution uses a Union-Find algorithm to detect overlapping markers (within 60px threshold) and spreads them radially around their centroid with adaptive radius scaling based on cluster size. Key implementation details:
Test coverage: 15 unit tests for core algorithm + bitmap symmetry test + deduplication test + UI tests Architecture highlights:
Confidence Score: 5/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User toggles declutter in Settings] --> B[SettingsViewModel.setMapMarkerDeclutterEnabled]
B --> C[SettingsRepository saves to DataStore]
C --> D[mapMarkerDeclutterEnabledFlow emits]
D --> E[MapViewModel collects flow]
E --> F[MapState.mapMarkerDeclutterEnabled updates]
F --> G[MapScreen LaunchedEffect triggers]
H[Contact markers update] --> G
I[Camera idle pan/zoom] --> J[onCameraIdleListener]
J --> K[updateDeclutterSources]
G --> K
K --> L{declutterEnabled?}
L -->|Yes| M[Project markers to screen space]
M --> N[MarkerDeclutter.calculateDeclutteredPositions]
N --> O[Union-Find groups overlapping markers]
O --> P[Spread groups radially with adaptive radius]
P --> Q[Convert back to lat/lng]
Q --> R[Update marker GeoJSON with display positions]
R --> S[Create pin/line GeoJSON for offset markers]
L -->|No| T[Use original GPS positions]
T --> R
S --> U[Render map with decluttered markers]
Last reviewed commit: 49e26d4 |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
I really dislike this. Please make a option to not have it turned on when you do not like it. |
|
Where would you set the option ? |
|
Settings -> Map Sources In combination with a separate PR renaming 'Map Sources' to 'Map' |
|
done |
Detect overlapping markers using screen-space proximity (Union-Find grouping) and spread them radially around their centroid with connecting lines to the original GPS positions. - Extract declutter algorithm to MarkerDeclutter.kt with testable API - Add ScreenToLatLng interface to abstract MapLibre projection - Add pin (CircleLayer) and line (LineLayer) sources for GPS points - Sort markers by angle from centroid to prevent line crossing - Scale radius adaptively based on group size - Recalculate on camera idle (zoom/pan) for dynamic updates - Pad marker bitmaps symmetrically for iconAnchor(center) alignment - Add 15 unit tests for declutter algorithm (MarkerDeclutterTest) - Add bitmap symmetry test (MarkerBitmapFactoryTest)
06feffc to
9355163
Compare
Summary
When multiple contacts share nearby GPS positions, their map markers overlap and become unreadable. This PR adds a custom decluttering algorithm that detects overlapping markers and spreads them radially, with thin lines connecting each displaced marker back to its true GPS position.
What it does
onCameraIdleListenericonAnchor("center")positions the circle correctlyArchitecture
MarkerDeclutter.kt— pure algorithm withScreenToLatLnginterface for testability (no MapLibre dependency)MapScreen.kt— integration: projects markers, creates GeoJSON sources/layersMarkerBitmapFactory.kt— top padding for vertical symmetryTests
MarkerDeclutterTest.kt: empty input, single marker, isolated pairs, overlapping pairs, equidistant offsets, multiple clusters, mixed isolated/clustered, large groups, radius scaling, custom thresholds, hash preservation, transitive groupingMarkerBitmapFactoryTest.ktScreenshots
Update: marker declutter is now optional (Map settings)
Following feedback, marker decluttering is now user-configurable in Settings.
What changed