@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@navigoo/map-components",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Reusable React components for mapping and routing in Yaoundé",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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.4, // ✅ Souple — permet un léger glissement
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
- }, [apiClient]);
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 polyline = L.polyline(coordinates, { color, weight: 4, opacity: 0.8 })
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', () => setSelectedRouteIndex(index));
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 intelligent de la vue sans sortir du Cameroun
129
- const routeBounds = L.latLngBounds(allCoordinates);
130
- const mergedBounds = routeBounds.extend(CAMEROON_BOUNDS);
131
- mapRef.current.fitBounds(mergedBounds, { padding: [30, 30] });
132
- } else {
133
- // 🌍 Recentrage sur le Cameroun si aucun itinéraire
134
- mapRef.current.fitBounds(CAMEROON_BOUNDS, { animate: true });
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