Skip to content

Commit bf445a9

Browse files
authored
Merge pull request #223 from WISE-Developers/MapLibre
migrate: Mapbox GL to MapLibre GL with TerraDraw
2 parents 10866fc + d656282 commit bf445a9

File tree

17 files changed

+2734
-608
lines changed

17 files changed

+2734
-608
lines changed

frontend/package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,22 @@
3131
"bump": "npm version patch --no-git-tag-version"
3232
},
3333
"dependencies": {
34-
"@mapbox/mapbox-gl-draw": "^1.5.1",
3534
"@turf/turf": "^7.3.1",
3635
"better-auth": "^1.5.5",
3736
"html2canvas": "^1.4.1",
3837
"jspdf": "^4.2.0",
39-
"mapbox-gl": "^3.16.0",
38+
"maplibre-gl": "^5.3.0",
4039
"react": "^18.3.1",
4140
"react-dom": "^18.3.1",
42-
"react-rnd": "^10.5.2"
41+
"react-rnd": "^10.5.2",
42+
"terra-draw": "^1.26.0",
43+
"terra-draw-maplibre-gl-adapter": "^1.3.0"
4344
},
4445
"devDependencies": {
4546
"@playwright/test": "^1.58.2",
4647
"@testing-library/jest-dom": "^6.9.1",
4748
"@testing-library/react": "^16.3.1",
4849
"@testing-library/user-event": "^14.6.1",
49-
"@types/mapbox__mapbox-gl-draw": "^1.4.9",
50-
"@types/mapbox-gl": "^3.4.1",
5150
"@types/react": "^18.3.12",
5251
"@types/react-dom": "^18.3.1",
5352
"@typescript-eslint/eslint-plugin": "^8.13.0",

frontend/src/features/Map/components/MapCapture.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export function MapCapture() {
7272
backgroundColor: null,
7373
ignoreElements: (el) => {
7474
if (el.tagName === 'CANVAS') return true;
75-
if (el.classList?.contains('mapboxgl-ctrl')) return true;
75+
if (el.classList?.contains('maplibregl-ctrl')) return true;
7676
if (el.classList?.contains('drawing-toolbar')) return true;
7777
if (el.classList?.contains('layer-panel')) return true;
7878
if (el.classList?.contains('layer-panel-toggle')) return true;

frontend/src/features/Map/components/MapContainer.tsx

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useEffect, useRef, ReactNode } 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 { useMapInternal } from '../context/MapContext';
55
import { DrawProvider } from '../context/DrawContext';
66
import { MapOptions, DEFAULT_MAP_OPTIONS, BASEMAP_STYLES, BasemapStyle } from '../types';
@@ -59,22 +59,12 @@ export function MapContainer({
5959
style,
6060
}: MapContainerProps) {
6161
const containerRef = useRef<HTMLDivElement>(null);
62-
const mapRef = useRef<mapboxgl.Map | null>(null);
62+
const mapRef = useRef<maplibregl.Map | null>(null);
6363
const { setMap, setIsLoaded, setIsLoading, setError } = useMapInternal();
6464

6565
useEffect(() => {
6666
if (!containerRef.current) return;
6767

68-
// Get access token from environment
69-
const accessToken = import.meta.env.VITE_MAPBOX_TOKEN;
70-
if (!accessToken) {
71-
setError(new Error('VITE_MAPBOX_TOKEN environment variable is not set'));
72-
setIsLoading(false);
73-
return;
74-
}
75-
76-
mapboxgl.accessToken = accessToken;
77-
7868
// Merge options with defaults
7969
const mergedOptions = { ...DEFAULT_MAP_OPTIONS, ...options };
8070

@@ -107,15 +97,15 @@ export function MapContainer({
10797
setIsLoading(true);
10898
setError(null);
10999

110-
const map = new mapboxgl.Map({
100+
const map = new maplibregl.Map({
111101
container: containerRef.current,
112102
style: initialStyle,
113103
center: initialCenter,
114104
zoom: initialZoom,
115105
pitch: initialPitch,
116106
bearing: initialBearing,
117-
attributionControl: true,
118-
preserveDrawingBuffer: true, // Needed for export/screenshots
107+
attributionControl: { compact: true },
108+
canvasContextAttributes: { preserveDrawingBuffer: true }, // Required for useRasterHover (gl.readPixels)
119109
});
120110

121111
mapRef.current = map;
@@ -125,23 +115,26 @@ export function MapContainer({
125115
setIsLoaded(true);
126116
setIsLoading(false);
127117

128-
// Add terrain if enabled
129-
if (mergedOptions.terrain) {
130-
map.addSource('mapbox-dem', {
131-
type: 'raster-dem',
132-
url: 'mapbox://mapbox.mapbox-terrain-dem-v1',
133-
tileSize: 512,
134-
maxzoom: 14,
135-
});
136-
map.setTerrain({
137-
source: 'mapbox-dem',
138-
exaggeration: mergedOptions.terrainExaggeration,
139-
});
140-
}
118+
// Terrain disabled - requires DEM source configuration
119+
// Mapbox DEM is not compatible with MapLibre
120+
// To enable, configure a compatible DEM source (e.g., MapTiler, self-hosted)
121+
// See useTerrain.ts for details
122+
// if (mergedOptions.terrain) {
123+
// map.addSource('terrain-dem', {
124+
// type: 'raster-dem',
125+
// url: 'YOUR_DEM_SOURCE_URL',
126+
// tileSize: 512,
127+
// maxzoom: 14,
128+
// });
129+
// map.setTerrain({
130+
// source: 'terrain-dem',
131+
// exaggeration: mergedOptions.terrainExaggeration,
132+
// });
133+
// }
141134

142135
// Add navigation controls
143-
map.addControl(new mapboxgl.NavigationControl(), 'top-right');
144-
map.addControl(new mapboxgl.ScaleControl({ unit: 'metric' }), 'bottom-left');
136+
map.addControl(new maplibregl.NavigationControl(), 'top-right');
137+
map.addControl(new maplibregl.ScaleControl({ unit: 'metric' }), 'bottom-left');
145138
});
146139

147140
// Save map view position on move end

frontend/src/features/Map/components/MapContextMenu.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import { useState, useEffect, useCallback, useRef } from 'react';
10+
import type { MapMouseEvent, MapTouchEvent } from 'maplibre-gl';
1011
import { useMap } from '../context/MapContext';
1112

1213
interface ContextMenuState {
@@ -58,7 +59,7 @@ export function MapContextMenu() {
5859

5960
// Handle context menu (right-click)
6061
const handleContextMenu = useCallback(
61-
(e: mapboxgl.MapMouseEvent & { originalEvent: MouseEvent }) => {
62+
(e: MapMouseEvent & { originalEvent: MouseEvent }) => {
6263
e.originalEvent.preventDefault();
6364

6465
if (!map) return;
@@ -79,7 +80,7 @@ export function MapContextMenu() {
7980

8081
// Handle touch start (for long press)
8182
const handleTouchStart = useCallback(
82-
(e: mapboxgl.MapTouchEvent) => {
83+
(e: MapTouchEvent) => {
8384
if (!map) return;
8485

8586
const touch = e.originalEvent.touches[0];

frontend/src/features/Map/components/MapInfoControl.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
import { useState, useEffect } from 'react';
9+
import type { MapMouseEvent } from 'maplibre-gl';
910
import { useMap } from '../context/MapContext';
1011

1112
/**
@@ -28,7 +29,7 @@ export function MapInfoControl() {
2829
setPitch(map.getPitch());
2930

3031
// Track cursor position
31-
const handleMouseMove = (e: mapboxgl.MapMouseEvent) => {
32+
const handleMouseMove = (e: MapMouseEvent) => {
3233
setCursorLat(e.lngLat.lat);
3334
setCursorLng(e.lngLat.lng);
3435
};

0 commit comments

Comments
 (0)