@navigoo/map-components 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/MapView.tsx +148 -13
package/package.json
CHANGED
|
@@ -26,6 +26,8 @@ const MapView: React.FC<MapViewProps> = ({
|
|
|
26
26
|
const mapContainerRef = useRef<HTMLDivElement>(null);
|
|
27
27
|
const routeLayerRef = useRef<L.LayerGroup | null>(null);
|
|
28
28
|
const routePolylinesRef = useRef<L.Polyline[]>([]);
|
|
29
|
+
const searchMarkerRef = useRef<L.Marker | null>(null);
|
|
30
|
+
const userMarkerRef = useRef<L.Marker | null>(null);
|
|
29
31
|
|
|
30
32
|
// ✅ Bornes élargies du Cameroun
|
|
31
33
|
const CAMEROON_BOUNDS = L.latLngBounds(
|
|
@@ -66,7 +68,7 @@ const MapView: React.FC<MapViewProps> = ({
|
|
|
66
68
|
minZoom: 5,
|
|
67
69
|
maxZoom,
|
|
68
70
|
maxBounds: CAMEROON_BOUNDS,
|
|
69
|
-
maxBoundsViscosity: 0.
|
|
71
|
+
maxBoundsViscosity: 0.8
|
|
70
72
|
});
|
|
71
73
|
|
|
72
74
|
// 🗺 Couche OpenStreetMap
|
|
@@ -95,16 +97,27 @@ const MapView: React.FC<MapViewProps> = ({
|
|
|
95
97
|
mapRef.current?.remove();
|
|
96
98
|
mapRef.current = null;
|
|
97
99
|
};
|
|
98
|
-
}, [
|
|
100
|
+
}, []);
|
|
99
101
|
|
|
100
|
-
// 🚗 Affichage des itinéraires
|
|
102
|
+
// 🚗 Affichage des itinéraires, lieux recherchés et position utilisateur
|
|
101
103
|
useEffect(() => {
|
|
102
104
|
if (!mapRef.current) return;
|
|
103
105
|
|
|
104
106
|
// Nettoyage avant rendu
|
|
105
107
|
routeLayerRef.current?.clearLayers();
|
|
106
108
|
routePolylinesRef.current = [];
|
|
109
|
+
|
|
110
|
+
// Nettoyer les anciens marqueurs
|
|
111
|
+
if (searchMarkerRef.current) {
|
|
112
|
+
searchMarkerRef.current.remove();
|
|
113
|
+
searchMarkerRef.current = null;
|
|
114
|
+
}
|
|
115
|
+
if (userMarkerRef.current) {
|
|
116
|
+
userMarkerRef.current.remove();
|
|
117
|
+
userMarkerRef.current = null;
|
|
118
|
+
}
|
|
107
119
|
|
|
120
|
+
// ✅ PRIORITÉ 1 : Affichage des itinéraires
|
|
108
121
|
if (routes && routes.length > 0) {
|
|
109
122
|
let allCoordinates: [number, number][] = [];
|
|
110
123
|
|
|
@@ -117,23 +130,145 @@ const MapView: React.FC<MapViewProps> = ({
|
|
|
117
130
|
|
|
118
131
|
if (coordinates.length > 0) {
|
|
119
132
|
const color = index === selectedRouteIndex ? 'green' : 'black';
|
|
120
|
-
const
|
|
133
|
+
const weight = index === selectedRouteIndex ? 5 : 3;
|
|
134
|
+
const opacity = index === selectedRouteIndex ? 1.0 : 0.5;
|
|
135
|
+
|
|
136
|
+
const polyline = L.polyline(coordinates, { color, weight, opacity })
|
|
121
137
|
.addTo(routeLayerRef.current!)
|
|
122
|
-
.on('click', () =>
|
|
138
|
+
.on('click', (e: L.LeafletMouseEvent) => {
|
|
139
|
+
L.DomEvent.stopPropagation(e);
|
|
140
|
+
setSelectedRouteIndex(index);
|
|
141
|
+
|
|
142
|
+
// Mettre à jour les styles de toutes les polylines
|
|
143
|
+
routePolylinesRef.current.forEach((pl, i) => {
|
|
144
|
+
pl.setStyle({
|
|
145
|
+
color: i === index ? 'green' : 'black',
|
|
146
|
+
weight: i === index ? 5 : 3,
|
|
147
|
+
opacity: i === index ? 1.0 : 0.5,
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Afficher un popup au centre de la route
|
|
152
|
+
const bounds = polyline.getBounds();
|
|
153
|
+
const center = bounds.getCenter();
|
|
154
|
+
L.popup()
|
|
155
|
+
.setLatLng(center)
|
|
156
|
+
.setContent(`
|
|
157
|
+
<b>Route ${index + 1}</b><br>
|
|
158
|
+
Distance: ${route.distance.toFixed(2)} m<br>
|
|
159
|
+
Durée: ${(route.duration / 60).toFixed(2)} min<br>
|
|
160
|
+
Départ: ${route.startPlaceName || 'Départ'}<br>
|
|
161
|
+
Destination: ${route.endPlaceName || 'Destination'}
|
|
162
|
+
`)
|
|
163
|
+
.openOn(mapRef.current!);
|
|
164
|
+
});
|
|
165
|
+
|
|
123
166
|
routePolylinesRef.current.push(polyline);
|
|
124
167
|
allCoordinates.push(...coordinates);
|
|
168
|
+
|
|
169
|
+
// Ajouter des marqueurs de départ et d'arrivée pour la route sélectionnée
|
|
170
|
+
if (index === selectedRouteIndex) {
|
|
171
|
+
const startPoint = coordinates[0];
|
|
172
|
+
const endPoint = coordinates[coordinates.length - 1];
|
|
173
|
+
|
|
174
|
+
// Marqueur de départ
|
|
175
|
+
L.marker(startPoint, {
|
|
176
|
+
icon: L.icon({
|
|
177
|
+
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
|
|
178
|
+
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
|
|
179
|
+
iconSize: [25, 41],
|
|
180
|
+
iconAnchor: [12, 41],
|
|
181
|
+
popupAnchor: [1, -34],
|
|
182
|
+
shadowSize: [41, 41]
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
.addTo(routeLayerRef.current!)
|
|
186
|
+
.bindPopup(`
|
|
187
|
+
<b>${route.startPlaceName || 'Départ'}</b><br>
|
|
188
|
+
Lat: ${startPoint[0].toFixed(6)}<br>
|
|
189
|
+
Lng: ${startPoint[1].toFixed(6)}
|
|
190
|
+
`);
|
|
191
|
+
|
|
192
|
+
// Marqueur d'arrivée
|
|
193
|
+
L.marker(endPoint, {
|
|
194
|
+
icon: L.icon({
|
|
195
|
+
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png',
|
|
196
|
+
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
|
|
197
|
+
iconSize: [25, 41],
|
|
198
|
+
iconAnchor: [12, 41],
|
|
199
|
+
popupAnchor: [1, -34],
|
|
200
|
+
shadowSize: [41, 41]
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
.addTo(routeLayerRef.current!)
|
|
204
|
+
.bindPopup(`
|
|
205
|
+
<b>${route.endPlaceName || 'Destination'}</b><br>
|
|
206
|
+
Lat: ${endPoint[0].toFixed(6)}<br>
|
|
207
|
+
Lng: ${endPoint[1].toFixed(6)}
|
|
208
|
+
`);
|
|
209
|
+
}
|
|
125
210
|
}
|
|
126
211
|
});
|
|
127
212
|
|
|
128
|
-
// 🗺 Ajustement
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
213
|
+
// 🗺 Ajustement de la vue sur l'itinéraire
|
|
214
|
+
if (allCoordinates.length > 0) {
|
|
215
|
+
const routeBounds = L.latLngBounds(allCoordinates);
|
|
216
|
+
mapRef.current.fitBounds(routeBounds, { padding: [50, 50], animate: true });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// ✅ PRIORITÉ 2 : Affichage du lieu recherché (seulement s'il n'y a pas de routes)
|
|
220
|
+
else if (searchedPlace && searchedPlace.coordinates) {
|
|
221
|
+
const { lat, lng } = searchedPlace.coordinates;
|
|
222
|
+
|
|
223
|
+
searchMarkerRef.current = L.marker([lat, lng], {
|
|
224
|
+
icon: L.icon({
|
|
225
|
+
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-blue.png',
|
|
226
|
+
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
|
|
227
|
+
iconSize: [25, 41],
|
|
228
|
+
iconAnchor: [12, 41],
|
|
229
|
+
popupAnchor: [1, -34],
|
|
230
|
+
shadowSize: [41, 41]
|
|
231
|
+
})
|
|
232
|
+
})
|
|
233
|
+
.addTo(mapRef.current!)
|
|
234
|
+
.bindPopup(`
|
|
235
|
+
<b>${searchedPlace.name}</b><br>
|
|
236
|
+
Lat: ${lat.toFixed(6)}<br>
|
|
237
|
+
Lng: ${lng.toFixed(6)}
|
|
238
|
+
`)
|
|
239
|
+
.openPopup();
|
|
240
|
+
|
|
241
|
+
mapRef.current.setView([lat, lng], 14, { animate: true });
|
|
242
|
+
}
|
|
243
|
+
// ✅ PRIORITÉ 3 : Affichage de la position utilisateur (seulement s'il n'y a ni routes ni lieu recherché)
|
|
244
|
+
else if (userLocation) {
|
|
245
|
+
const { latitude, longitude } = userLocation;
|
|
246
|
+
|
|
247
|
+
userMarkerRef.current = L.marker([latitude, longitude], {
|
|
248
|
+
icon: L.icon({
|
|
249
|
+
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-violet.png',
|
|
250
|
+
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
|
|
251
|
+
iconSize: [25, 41],
|
|
252
|
+
iconAnchor: [12, 41],
|
|
253
|
+
popupAnchor: [1, -34],
|
|
254
|
+
shadowSize: [41, 41]
|
|
255
|
+
})
|
|
256
|
+
})
|
|
257
|
+
.addTo(mapRef.current!)
|
|
258
|
+
.bindPopup(`
|
|
259
|
+
<b>Votre position</b><br>
|
|
260
|
+
Lat: ${latitude.toFixed(6)}<br>
|
|
261
|
+
Lng: ${longitude.toFixed(6)}
|
|
262
|
+
`)
|
|
263
|
+
.openPopup();
|
|
264
|
+
|
|
265
|
+
mapRef.current.setView([latitude, longitude], 14, { animate: true });
|
|
266
|
+
}
|
|
267
|
+
// ✅ PRIORITÉ 4 : Recentrage sur le Cameroun par défaut
|
|
268
|
+
else {
|
|
269
|
+
mapRef.current.fitBounds(CAMEROON_BOUNDS, { animate: true, padding: [20, 20] });
|
|
135
270
|
}
|
|
136
|
-
}, [routes, selectedRouteIndex]);
|
|
271
|
+
}, [routes, selectedRouteIndex, searchedPlace, userLocation, setSelectedRouteIndex]);
|
|
137
272
|
|
|
138
273
|
return (
|
|
139
274
|
<div
|