Skip to content

Commit 3037044

Browse files
Merge branch 'feat/6719-migrate-mapboxgl-to-maplibre' into deployment/naxa
2 parents 38df46c + e9f1ffd commit 3037044

19 files changed

Lines changed: 271 additions & 648 deletions

File tree

frontend/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
"@hotosm/id": "^2.34.0",
88
"@hotosm/iso-countries-languages": "^1.1.2",
99
"@mapbox/mapbox-gl-draw": "^1.4.3",
10-
"@mapbox/mapbox-gl-geocoder": "^5.0.2",
1110
"@mapbox/mapbox-gl-language": "^0.10.1",
11+
"@maplibre/maplibre-gl-geocoder": "^1.9.0",
1212
"@placemarkio/geo-viewport": "^1.0.2",
1313
"@rapideditor/rapid": "^2.5.2",
1414
"@sentry/react": "^7.102.0",
@@ -36,8 +36,8 @@
3636
"fromentries": "^1.3.2",
3737
"h3-js": "^4.1.0",
3838
"humanize-duration": "^3.31.0",
39-
"mapbox-gl": "^1.13.3",
4039
"mapbox-gl-draw-rectangle-mode": "^1.0.4",
40+
"maplibre-gl": "^5.6.0",
4141
"marked": "^4.3.0",
4242
"osmtogeojson": "^3.0.0-beta.5",
4343
"prop-types": "^15.8.1",

frontend/src/assets/styles/_extra.scss

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -295,12 +295,6 @@ div.messageBodyLinks {
295295
width: calc(100% - 4rem);
296296
}
297297

298-
.mapbox-improve-map,
299-
a[href="https://www.mapbox.com/map-feedback/"]
300-
{
301-
display: none;
302-
}
303-
304298
.object-fit-cover {
305299
object-fit: cover;
306300
}
@@ -366,7 +360,7 @@ a[href="https://www.mapbox.com/map-feedback/"]
366360

367361
#project-creation-map,
368362
#priority-area-map {
369-
.mapboxgl-ctrl-top-right {
363+
.maplibregl-ctrl-top-right {
370364
top: 2.5rem;
371365
}
372366
}

frontend/src/components/partnerMapswipeStats/contributionsHeatmap.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import React, { useEffect, useRef } from 'react';
2-
import mapboxgl from 'mapbox-gl';
2+
import maplibregl from 'maplibre-gl';
33
import { latLngToCell, cellToBoundary } from 'h3-js';
44
import { FormattedMessage } from 'react-intl';
55
import PropTypes from 'prop-types';
6-
import 'mapbox-gl/dist/mapbox-gl.css';
6+
import 'maplibre-gl/dist/maplibre-gl.css';
77

88
import { MAPBOX_TOKEN, MAP_STYLE, CHART_COLOURS } from '../../config';
99
import messages from './messages';
1010
import './contributionsHeatmap.css';
1111

12-
mapboxgl.accessToken = MAPBOX_TOKEN;
12+
maplibregl.accessToken = MAPBOX_TOKEN;
1313

1414
export const ContributionsHeatmap = ({ contributionsByGeo = [] }) => {
1515
const mapContainer = useRef(null);
@@ -18,15 +18,15 @@ export const ContributionsHeatmap = ({ contributionsByGeo = [] }) => {
1818
useEffect(() => {
1919
if (map.current) return; // initialize map only once
2020

21-
map.current = new mapboxgl.Map({
21+
map.current = new maplibregl.Map({
2222
container: mapContainer.current,
2323
style: MAP_STYLE,
2424
center: [0, 0],
2525
zoom: 1.25,
2626
});
2727

2828
map.current.scrollZoom.disable();
29-
map.current.addControl(new mapboxgl.NavigationControl());
29+
map.current.addControl(new maplibregl.NavigationControl());
3030

3131
const getStyle = (row) => {
3232
const styles = [

frontend/src/components/projectCreate/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useNavigate } from 'react-router-dom';
44
import { useQueryParam, NumberParam } from 'use-query-params';
55
import { FormattedMessage, FormattedNumber, useIntl } from 'react-intl';
66
import ReactPlaceholder from 'react-placeholder';
7-
import { supported } from 'mapbox-gl';
87
import area from '@turf/area';
98
import bbox from '@turf/bbox';
109
import { featureCollection } from '@turf/helpers';
@@ -25,6 +24,7 @@ import NavButtons from './navButtons';
2524
import Review from './review';
2625
import { Alert } from '../alert';
2726
import { makeGrid } from '../../utils/taskGrid';
27+
import isWebglSupported from '../../utils/isWebglSupported';
2828
import { MAX_AOI_AREA } from '../../config';
2929
import {
3030
verifyGeometry,
@@ -303,7 +303,7 @@ const ProjectCreate = () => {
303303
showProjectsAOILayer={showProjectsAOILayer}
304304
/>
305305
</Suspense>
306-
{supported() && (
306+
{isWebglSupported() && (
307307
<>
308308
<div className="cf absolute bg-white o-90 top-1 left-1 pa3 mw6">
309309
{cloneFromId && (

frontend/src/components/projectCreate/projectCreationMap.js

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,26 @@
11
import { useLayoutEffect, useEffect, useCallback, useState, createRef } from 'react';
22
import { useSelector } from 'react-redux';
3-
import mapboxgl from 'mapbox-gl';
4-
import 'mapbox-gl/dist/mapbox-gl.css';
3+
import maplibregl from 'maplibre-gl';
4+
import 'maplibre-gl/dist/maplibre-gl.css';
55
import { featureCollection } from '@turf/helpers';
66
import MapboxLanguage from '@mapbox/mapbox-gl-language';
7-
import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder';
8-
import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css';
7+
import MaplibreGeocoder from '@maplibre/maplibre-gl-geocoder';
8+
import '@maplibre/maplibre-gl-geocoder/dist/maplibre-gl-geocoder.css';
99
import { useDropzone } from 'react-dropzone';
1010

11-
import { mapboxLayerDefn } from '../projects/projectsMap';
11+
import { maplibreLayerDefn } from '../projects/projectsMap';
1212
import useMapboxSupportedLanguage from '../../hooks/UseMapboxSupportedLanguage';
1313

14-
import {
15-
MAPBOX_TOKEN,
16-
MAP_STYLE,
17-
CHART_COLOURS,
18-
MAPBOX_RTL_PLUGIN_URL,
19-
TASK_COLOURS,
20-
} from '../../config';
14+
import { MAPBOX_TOKEN, MAP_STYLE, CHART_COLOURS, TASK_COLOURS } from '../../config';
2115
import { fetchLocalJSONAPI } from '../../network/genericJSONRequest';
2216
import { useDebouncedCallback } from '../../hooks/UseThrottle';
17+
import isWebglSupported from '../../utils/isWebglSupported';
18+
import useSetRTLTextPlugin from '../../utils/useSetRTLTextPlugin';
2319
import { BasemapMenu } from '../basemapMenu';
2420
import { ProjectsAOILayerCheckBox } from './projectsAOILayerCheckBox';
2521
import WebglUnsupported from '../webglUnsupported';
2622

27-
mapboxgl.accessToken = MAPBOX_TOKEN;
28-
try {
29-
mapboxgl.setRTLTextPlugin(MAPBOX_RTL_PLUGIN_URL);
30-
} catch {
31-
console.log('RTLTextPlugin is loaded');
32-
}
23+
maplibregl.accessToken = MAPBOX_TOKEN;
3324

3425
const ProjectCreationMap = ({ mapObj, setMapObj, metadata, updateMetadata, step, uploadFile }) => {
3526
const mapRef = createRef();
@@ -47,6 +38,8 @@ const ProjectCreationMap = ({ mapObj, setMapObj, metadata, updateMetadata, step,
4738
});
4839
const minZoomLevelToAOIVisualization = 9;
4940

41+
useSetRTLTextPlugin();
42+
5043
useEffect(() => {
5144
fetchLocalJSONAPI('projects/').then((res) => setExistingProjectsList(res.mapResults));
5245
}, []);
@@ -78,22 +71,22 @@ const ProjectCreationMap = ({ mapObj, setMapObj, metadata, updateMetadata, step,
7871
}, [showProjectsAOILayer, debouncedGetProjectsAOI, clearProjectsAOI, step]);
7972

8073
useLayoutEffect(() => {
81-
if (!mapboxgl.supported()) return;
82-
const map = new mapboxgl.Map({
74+
if (!isWebglSupported()) return;
75+
const map = new maplibregl.Map({
8376
container: mapRef.current,
8477
style: MAP_STYLE,
8578
center: [0, 0],
8679
zoom: 1.3,
8780
attributionControl: false,
8881
})
89-
.addControl(new mapboxgl.AttributionControl({ compact: false }))
82+
.addControl(new maplibregl.AttributionControl({ compact: false }))
9083
.addControl(new MapboxLanguage({ defaultLanguage: mapboxSupportedLanguage }))
91-
.addControl(new mapboxgl.ScaleControl({ unit: 'metric' }));
84+
.addControl(new maplibregl.ScaleControl({ unit: 'metric' }));
9285
if (MAPBOX_TOKEN) {
9386
map.addControl(
94-
new MapboxGeocoder({
87+
new MaplibreGeocoder({
9588
accessToken: MAPBOX_TOKEN,
96-
mapboxgl: mapboxgl,
89+
maplibregl,
9790
marker: false,
9891
collapsed: true,
9992
language: mapboxSupportedLanguage,
@@ -222,9 +215,9 @@ const ProjectCreationMap = ({ mapObj, setMapObj, metadata, updateMetadata, step,
222215

223216
/* set up style/sources for the map, either immediately or on base load */
224217
if (mapReadyProjectsReady) {
225-
mapboxLayerDefn(map, existingProjectsList, noop, true);
218+
maplibreLayerDefn(map, existingProjectsList, noop, true);
226219
} else if (projectsReadyMapLoading) {
227-
map.on('load', () => mapboxLayerDefn(map, existingProjectsList, noop, true));
220+
map.on('load', () => maplibreLayerDefn(map, existingProjectsList, noop, true));
228221
}
229222

230223
/* refill the source on existingProjectsList changes */
@@ -234,17 +227,17 @@ const ProjectCreationMap = ({ mapObj, setMapObj, metadata, updateMetadata, step,
234227
}, [mapObj, existingProjectsList]);
235228

236229
useLayoutEffect(() => {
237-
if (mapObj.map !== null && mapboxgl.supported()) {
230+
if (mapObj.map !== null && isWebglSupported()) {
238231
mapObj.map.on('moveend', (event) => {
239232
debouncedGetProjectsAOI();
240233
});
241234
}
242235
});
243236

244237
useLayoutEffect(() => {
245-
if (mapObj.map !== null && mapboxgl.supported()) {
238+
if (mapObj.map !== null && isWebglSupported()) {
246239
mapObj.map.on('load', () => {
247-
mapObj.map.addControl(new mapboxgl.NavigationControl());
240+
mapObj.map.addControl(new maplibregl.NavigationControl());
248241
mapObj.map.addControl(mapObj.draw);
249242
addMapLayers(mapObj.map);
250243
});
@@ -282,7 +275,7 @@ const ProjectCreationMap = ({ mapObj, setMapObj, metadata, updateMetadata, step,
282275
}
283276
}, [mapObj, metadata, updateMetadata, step]);
284277

285-
if (!mapboxgl.supported()) {
278+
if (!isWebglSupported()) {
286279
return <WebglUnsupported className="vh-50 h-100-l w-100" />;
287280
} else {
288281
return (

frontend/src/components/projectCreate/tests/setTaskSizes.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { render, screen } from '@testing-library/react';
22
import '@testing-library/jest-dom';
3-
import mapboxgl from 'mapbox-gl';
3+
import maplibregl from 'maplibre-gl';
44

55
import SetTaskSizes from '../setTaskSizes';
66
import { projectMetadata } from '../../../utils/tests/snippets/projectMetadata';
77
import { IntlProviders } from '../../../utils/testWithIntl';
88

9-
jest.mock('mapbox-gl/dist/mapbox-gl', () => ({
9+
jest.mock('maplibre-gl/dist/maplibre-gl', () => ({
1010
GeolocateControl: jest.fn(),
1111
Map: jest.fn(() => ({
1212
addControl: jest.fn(),
@@ -20,7 +20,7 @@ jest.mock('mapbox-gl/dist/mapbox-gl', () => ({
2020
NavigationControl: jest.fn(),
2121
}));
2222

23-
const map = new mapboxgl.Map({
23+
const map = new maplibregl.Map({
2424
container: '',
2525
style: {},
2626
center: [0, 0],

frontend/src/components/projectDetail/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { Link, useParams } from 'react-router-dom';
33
import ReactPlaceholder from 'react-placeholder';
44
import centroid from '@turf/centroid';
55
import { FormattedMessage } from 'react-intl';
6-
import { supported } from 'mapbox-gl';
76
import PropTypes from 'prop-types';
87

98
import messages from './messages';
@@ -29,6 +28,7 @@ import './styles.scss';
2928
import { useWindowSize } from '../../hooks/UseWindowSize';
3029
import { DownloadOsmData } from './downloadOsmData.js';
3130
import { ENABLE_EXPORT_TOOL } from '../../config/index.js';
31+
import isWebglSupported from '../../utils/isWebglSupported';
3232

3333
/* lazy imports must be last import */
3434
const ProjectTimeline = lazy(() => import('./timeline' /* webpackChunkName: "timeline" */));
@@ -77,7 +77,7 @@ export const ProjectDetailMap = (props) => {
7777
loading={props.projectLoading}
7878
className="w-100 vh-75 h-100-l"
7979
/>
80-
{taskBordersOnly && supported() && (
80+
{taskBordersOnly && isWebglSupported() && (
8181
<div
8282
className="cf left-1 top-1 absolute zoom-to-task"
8383
style={{

frontend/src/components/projectEdit/priorityAreasForm.js

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useState, useContext, useLayoutEffect, createRef } from 'react';
2-
import mapboxgl from 'mapbox-gl';
3-
import 'mapbox-gl/dist/mapbox-gl.css';
2+
import maplibregl from 'maplibre-gl';
3+
import 'maplibre-gl/dist/maplibre-gl.css';
44
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
55
import MapboxDraw from '@mapbox/mapbox-gl-draw';
66
import DrawRectangle from 'mapbox-gl-draw-rectangle-mode';
@@ -13,32 +13,31 @@ import messages from './messages';
1313
import { StateContext, styleClasses } from '../../views/projectEdit';
1414
import { CustomButton } from '../button';
1515
import { MappedIcon, WasteIcon, MappedSquareIcon, FileImportIcon } from '../svgIcons';
16-
import { MAPBOX_TOKEN, MAP_STYLE, MAPBOX_RTL_PLUGIN_URL, CHART_COLOURS } from '../../config';
16+
import { MAPBOX_TOKEN, MAP_STYLE, CHART_COLOURS } from '../../config';
1717
import { BasemapMenu } from '../basemapMenu';
1818
import {
1919
verifyGeometry,
2020
readGeoFile,
2121
verifyFileFormat,
2222
verifyFileSize,
2323
} from '../../utils/geoFileFunctions';
24+
import isWebglSupported from '../../utils/isWebglSupported';
25+
import useSetRTLTextPlugin from '../../utils/useSetRTLTextPlugin';
2426
import { getErrorMsg } from '../projectCreate/fileUploadErrors';
2527
import { Alert } from '../alert';
2628
import WebglUnsupported from '../webglUnsupported';
2729
import useMapboxSupportedLanguage from '../../hooks/UseMapboxSupportedLanguage';
2830

29-
mapboxgl.accessToken = MAPBOX_TOKEN;
30-
try {
31-
mapboxgl.setRTLTextPlugin(MAPBOX_RTL_PLUGIN_URL);
32-
} catch {
33-
console.log('RTLTextPlugin is loaded');
34-
}
31+
maplibregl.accessToken = MAPBOX_TOKEN;
3532

3633
export const PriorityAreasForm = () => {
3734
const { projectInfo, setProjectInfo } = useContext(StateContext);
3835
const mapboxSupportedLanguage = useMapboxSupportedLanguage();
3936
const mapRef = createRef();
4037
const [error, setError] = useState({ error: false, message: null });
4138

39+
useSetRTLTextPlugin();
40+
4241
const modes = MapboxDraw.modes;
4342
modes.draw_rectangle = DrawRectangle;
4443
const drawOptions = {
@@ -120,17 +119,17 @@ export const PriorityAreasForm = () => {
120119

121120
useLayoutEffect(() => {
122121
const map =
123-
mapboxgl.supported() &&
124-
new mapboxgl.Map({
122+
isWebglSupported() &&
123+
new maplibregl.Map({
125124
container: mapRef.current,
126125
style: MAP_STYLE,
127126
center: [0, 0],
128127
zoom: 1,
129128
attributionControl: false,
130129
})
131-
.addControl(new mapboxgl.AttributionControl({ compact: false }))
130+
.addControl(new maplibregl.AttributionControl({ compact: false }))
132131
.addControl(new MapboxLanguage({ defaultLanguage: mapboxSupportedLanguage }))
133-
.addControl(new mapboxgl.NavigationControl());
132+
.addControl(new maplibregl.NavigationControl());
134133

135134
setMapObj({ ...mapObj, map: map });
136135

@@ -227,7 +226,7 @@ export const PriorityAreasForm = () => {
227226
};
228227

229228
useLayoutEffect(() => {
230-
if (mapObj.map !== null && mapboxgl.supported()) {
229+
if (mapObj.map !== null && isWebglSupported()) {
231230
mapObj.map.on('load', () => {
232231
mapObj.map.addControl(mapObj.draw);
233232
addMapLayers(mapObj.map);
@@ -254,7 +253,7 @@ export const PriorityAreasForm = () => {
254253
setProjectInfo({ ...projectInfo, priorityAreas: [] });
255254
};
256255

257-
if (!mapboxgl.supported()) {
256+
if (!isWebglSupported()) {
258257
return <WebglUnsupported className="vh-75 w-100 bg-white" />;
259258
} else {
260259
return (

0 commit comments

Comments
 (0)