diff --git a/client/src/components/Journey/JourneyMapGL.tsx b/client/src/components/Journey/JourneyMapGL.tsx index 3eb4f1cc7..c57d7c327 100644 --- a/client/src/components/Journey/JourneyMapGL.tsx +++ b/client/src/components/Journey/JourneyMapGL.tsx @@ -362,6 +362,9 @@ const JourneyMapGL = forwardRef(function JourneyMapGL antialias: mapboxQuality, } if (!isMapLibre) mapOptions.projection = mapboxQuality ? 'globe' : 'mercator' + // MapLibre 5's around-center mouse rotate ping-pongs near mid-screen (#1545) + // — see MapViewGL. Keep the plain dx-based rotate everywhere. + if (isMapLibre) mapOptions.aroundCenter = false const map = new gl.Map(mapOptions as any) mapRef.current = map diff --git a/client/src/components/Map/MapViewGL.test.tsx b/client/src/components/Map/MapViewGL.test.tsx index 7b4c7635e..f8786b106 100644 --- a/client/src/components/Map/MapViewGL.test.tsx +++ b/client/src/components/Map/MapViewGL.test.tsx @@ -244,6 +244,39 @@ describe('MapViewGL', () => { expect(mapboxgl.Map).not.toHaveBeenCalled() }) + it('FE-COMP-MAPVIEWGL-014: MapLibre maps disable the around-center mouse rotate (#1545)', async () => { + const mapboxgl = (await import('mapbox-gl')).default + const maplibregl = (await import('maplibre-gl')).default + useSettingsStore.setState({ + settings: { + ...useSettingsStore.getState().settings, + map_provider: 'maplibre-gl', + mapbox_access_token: '', + maplibre_style: 'https://tiles.openfreemap.org/styles/liberty', + }, + } as any) + const places = [buildMapPlace({ id: 1, lat: 48.8584, lng: 2.2945 })] + + render() + await act(async () => {}) + // MapLibre 5's around-center rotate reverses direction at a drifting + // mid-screen line, so the map must opt out of it. + expect((maplibregl.Map as any).mock.calls[0][0]).toMatchObject({ aroundCenter: false }) + + vi.clearAllMocks() + useSettingsStore.setState({ + settings: { + ...useSettingsStore.getState().settings, + map_provider: 'mapbox-gl', + mapbox_access_token: 'pk.test_token', + }, + } as any) + render() + await act(async () => {}) + // mapbox-gl has no such option — it must not receive the stray key. + expect((mapboxgl.Map as any).mock.calls[0][0]).not.toHaveProperty('aroundCenter') + }) + it('FE-COMP-MAPVIEWGL-005: adds the clustered place source + layers so markers group on zoom-out (#1385)', async () => { glMap.on.mockImplementation((event: string, handlerOrLayer: unknown) => { if (event === 'load' && typeof handlerOrLayer === 'function') (handlerOrLayer as () => void)() diff --git a/client/src/components/Map/MapViewGL.tsx b/client/src/components/Map/MapViewGL.tsx index cc79f6e78..50a84f981 100644 --- a/client/src/components/Map/MapViewGL.tsx +++ b/client/src/components/Map/MapViewGL.tsx @@ -291,6 +291,11 @@ export function MapViewGL({ antialias: mapboxQuality, } if (!isMapLibre) mapOptions.projection = mapboxQuality ? 'globe' : 'mercator' + // MapLibre 5's mouse-rotate inverts its sign at a mid-screen line it gets by + // re-projecting the map center — a line that drifts with the bearing, so a + // right-button drag near mid-screen ping-pongs instead of rotating (#1545). + // aroundCenter: false restores the plain dx-based rotate mapbox-gl uses. + if (isMapLibre) mapOptions.aroundCenter = false const map = new gl.Map(mapOptions as any) mapRef.current = map diff --git a/client/src/components/Settings/MapboxPreview.tsx b/client/src/components/Settings/MapboxPreview.tsx index 3f3362280..d3f0a33f3 100644 --- a/client/src/components/Settings/MapboxPreview.tsx +++ b/client/src/components/Settings/MapboxPreview.tsx @@ -43,6 +43,9 @@ export default function GlMapPreview({ provider = 'mapbox-gl', token = '', style antialias: quality, } if (!isMapLibre) mapOptions.projection = quality ? 'globe' : 'mercator' + // MapLibre 5's around-center mouse rotate ping-pongs near mid-screen (#1545) + // — see MapViewGL. Keep the plain dx-based rotate everywhere. + if (isMapLibre) mapOptions.aroundCenter = false const map = new gl.Map(mapOptions as any) mapRef.current = map