-
Notifications
You must be signed in to change notification settings - Fork 2.9k
/
MapView.web.tsx
119 lines (103 loc) · 4.4 KB
/
MapView.web.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Explanation: Different Mapbox libraries are required for web and native mobile platforms.
// This is why we have separate components for web and native to handle the specific implementations.
// For the web version, we use the Mapbox Web library called react-map-gl, while for the native mobile version,
// we utilize a different Mapbox library @rnmapbox/maps tailored for mobile development.
import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useState} from 'react';
import {View} from 'react-native';
import Map, {MapRef, Marker} from 'react-map-gl';
import mapboxgl from 'mapbox-gl';
import responder from './responder';
import utils from './utils';
import CONST from '../../CONST';
import * as StyleUtils from '../../styles/StyleUtils';
import themeColors from '../../styles/themes/default';
import Direction from './Direction';
import {MapViewHandle, MapViewProps} from './MapViewTypes';
import 'mapbox-gl/dist/mapbox-gl.css';
const MapView = forwardRef<MapViewHandle, MapViewProps>(
({style, styleURL, waypoints, mapPadding, accessToken, directionCoordinates, initialState = {location: CONST.MAPBOX.DEFAULT_COORDINATE, zoom: CONST.MAPBOX.DEFAULT_ZOOM}}, ref) => {
const [mapRef, setMapRef] = useState<MapRef | null>(null);
const setRef = useCallback((newRef: MapRef | null) => setMapRef(newRef), []);
useEffect(() => {
if (!waypoints || waypoints.length === 0) {
return;
}
if (!mapRef) {
return;
}
if (waypoints.length === 1) {
mapRef.flyTo({
center: waypoints[0].coordinate,
zoom: 15,
});
return;
}
const map = mapRef.getMap();
const {northEast, southWest} = utils.getBounds(
waypoints.map((waypoint) => waypoint.coordinate),
directionCoordinates,
);
map.fitBounds([northEast, southWest], {padding: mapPadding});
}, [waypoints, mapRef, mapPadding, directionCoordinates]);
useEffect(() => {
if (!mapRef) {
return;
}
const resizeObserver = new ResizeObserver(() => {
mapRef.resize();
});
resizeObserver.observe(mapRef.getContainer());
return () => {
resizeObserver?.disconnect();
};
}, [mapRef]);
useImperativeHandle(
ref,
() => ({
flyTo: (location: [number, number], zoomLevel: number = CONST.MAPBOX.DEFAULT_ZOOM, animationDuration?: number) =>
mapRef?.flyTo({
center: location,
zoom: zoomLevel,
duration: animationDuration,
}),
fitBounds: (northEast: [number, number], southWest: [number, number]) => mapRef?.fitBounds([northEast, southWest]),
}),
[mapRef],
);
return (
<View
style={style}
// eslint-disable-next-line
{...responder.panHandlers}
>
<Map
ref={setRef}
mapLib={mapboxgl}
mapboxAccessToken={accessToken}
initialViewState={{
longitude: initialState.location[0],
latitude: initialState.location[1],
zoom: initialState.zoom,
}}
style={StyleUtils.getTextColorStyle(themeColors.mapAttributionText) as React.CSSProperties}
mapStyle={styleURL}
>
{waypoints?.map(({coordinate, markerComponent, id}) => {
const MarkerComponent = markerComponent;
return (
<Marker
key={id}
longitude={coordinate[0]}
latitude={coordinate[1]}
>
<MarkerComponent />
</Marker>
);
})}
{directionCoordinates && <Direction coordinates={directionCoordinates} />}
</Map>
</View>
);
},
);
export default MapView;