@navigoo/map-components 1.0.8 → 1.0.9

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.0.8",
3
+ "version": "1.0.9",
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",
@@ -29,7 +29,7 @@ const MapView: React.FC<MapViewProps> = ({
29
29
  const clickMarkerRef = useRef<L.Marker | null>(null);
30
30
  const routePolylinesRef = useRef<L.Polyline[]>([]);
31
31
 
32
- // Définition des limites du Cameroun
32
+ // 📍 Définition des limites du Cameroun
33
33
  const CAMEROON_BOUNDS = L.latLngBounds(
34
34
  [1.65, 8.4], // Coin sud-ouest
35
35
  [13.08, 16.2] // Coin nord-est
@@ -60,25 +60,19 @@ const MapView: React.FC<MapViewProps> = ({
60
60
  if (mapContainerRef.current && !mapRef.current) {
61
61
  const maxZoom = 18;
62
62
 
63
- // Configuration de la carte avec limites strictes
63
+ // 🌍 Configuration initiale de la carte
64
64
  mapRef.current = L.map(mapContainerRef.current, {
65
- center: [5.5, 12.0], // Centre du Cameroun
66
- zoom: 6, // Zoom pour voir tout le Cameroun
67
- minZoom: 6,
68
- maxZoom: maxZoom,
65
+ center: [7.3697, 12.3547], // Centre géographique du Cameroun
66
+ zoom: 6,
67
+ minZoom: 5, // Permet un léger recul
68
+ maxZoom,
69
69
  maxBounds: CAMEROON_BOUNDS,
70
- maxBoundsViscosity: 1.0, // Empêche complètement le dépassement des limites
70
+ maxBoundsViscosity: 1.0,
71
71
  });
72
72
 
73
- // Forcer la carte à rester dans les limites initiales
74
- mapRef.current.setMaxBounds(CAMEROON_BOUNDS);
75
-
76
73
  L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
77
- attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
78
- maxZoom: maxZoom,
79
- tileSize: 256,
80
- zoomOffset: 0,
81
- bounds: CAMEROON_BOUNDS, // Limiter les tuiles aux bounds du Cameroun
74
+ attribution: '© OpenStreetMap contributors',
75
+ maxZoom,
82
76
  }).addTo(mapRef.current);
83
77
 
84
78
  L.Icon.Default.mergeOptions({
@@ -89,188 +83,55 @@ const MapView: React.FC<MapViewProps> = ({
89
83
 
90
84
  routeLayerRef.current = L.layerGroup().addTo(mapRef.current);
91
85
 
92
- // Recentrer la carte si l'utilisateur essaie de la faire sortir des limites
93
- mapRef.current.on('drag', () => {
94
- if (mapRef.current) {
95
- const currentCenter = mapRef.current.getCenter();
96
- const currentZoom = mapRef.current.getZoom();
97
-
98
- if (!CAMEROON_BOUNDS.contains(currentCenter)) {
99
- mapRef.current.panInsideBounds(CAMEROON_BOUNDS, { animate: true });
100
- }
101
- }
102
- });
103
-
104
- mapRef.current.on('click', async (e: L.LeafletMouseEvent) => {
105
- const { lat, lng } = e.latlng;
106
-
107
- // Vérifier que le clic est dans les limites du Cameroun
108
- if (!CAMEROON_BOUNDS.contains([lat, lng])) {
109
- return;
110
- }
111
-
112
- const closestPlace = await apiClient.findClosestPlace(lat, lng);
113
- const placeName = closestPlace?.name || 'Position sélectionnée';
114
-
115
- if (clickMarkerRef.current) {
116
- mapRef.current?.removeLayer(clickMarkerRef.current);
117
- }
118
-
119
- clickMarkerRef.current = L.marker([lat, lng])
120
- .addTo(mapRef.current!)
121
- .bindPopup(`<b>${placeName}</b><br>Lat: ${lat.toFixed(6)}<br>Lng: ${lng.toFixed(6)}`)
122
- .openPopup();
123
- });
86
+ // 🧭 Afficher tout le Cameroun dès le départ
87
+ mapRef.current.fitBounds(CAMEROON_BOUNDS, { animate: false });
124
88
  }
125
89
 
126
90
  return () => {
127
- if (mapRef.current) {
128
- mapRef.current.remove();
129
- mapRef.current = null;
130
- }
91
+ mapRef.current?.remove();
92
+ mapRef.current = null;
131
93
  };
132
94
  }, [apiClient]);
133
95
 
134
96
  useEffect(() => {
135
97
  if (!mapRef.current) return;
136
98
 
137
- // Nettoyer les couches précédentes
138
- if (routeLayerRef.current) {
139
- routeLayerRef.current.clearLayers();
140
- }
141
- if (markerRef.current) {
142
- markerRef.current.remove();
143
- markerRef.current = null;
144
- }
145
- if (clickMarkerRef.current) {
146
- clickMarkerRef.current.remove();
147
- clickMarkerRef.current = null;
148
- }
149
-
99
+ // Nettoyage
100
+ routeLayerRef.current?.clearLayers();
150
101
  routePolylinesRef.current = [];
151
102
 
152
- // Fonction pour centrer la carte sur un point avec un marqueur
153
- const centerOnPoint = async (lat: number, lng: number, placeName: string, zoom: number = 16) => {
154
- // Vérifier que le point est dans les limites du Cameroun
155
- if (!CAMEROON_BOUNDS.contains([lat, lng])) {
156
- console.warn('Le point est en dehors des limites du Cameroun');
157
- return;
158
- }
159
-
160
- let displayName = placeName;
161
- if (placeName === 'Votre position') {
162
- const closestPlace = await apiClient.findClosestPlace(lat, lng);
163
- displayName = closestPlace?.name || placeName;
164
- }
165
-
166
- // Supprimer l'ancien marqueur s'il existe
167
- if (markerRef.current) {
168
- markerRef.current.remove();
169
- markerRef.current = null;
170
- }
171
-
172
- mapRef.current!.setView([lat, lng], zoom, { animate: true });
173
- markerRef.current = L.marker([lat, lng])
174
- .addTo(mapRef.current!)
175
- .bindPopup(`<b>${displayName}</b><br>Lat: ${lat.toFixed(6)}<br>Lng: ${lng.toFixed(6)}`)
176
- .openPopup();
177
- };
178
-
179
103
  if (routes && routes.length > 0) {
180
- // Gérer les itinéraires
181
104
  let allCoordinates: [number, number][] = [];
105
+
182
106
  routes.forEach((route, index) => {
183
107
  const coordinates: [number, number][] = [];
184
- route.steps.forEach((step) => {
108
+ route.steps.forEach(step => {
185
109
  const latLngs = parseWKTLineString(step.geometry);
186
110
  if (latLngs.length > 0) coordinates.push(...latLngs);
187
111
  });
188
112
 
189
113
  if (coordinates.length > 0) {
190
114
  const color = index === selectedRouteIndex ? 'green' : 'black';
191
- const weight = index === selectedRouteIndex ? 5 : 3;
192
- const opacity = index === selectedRouteIndex ? 1.0 : 0.5;
193
-
194
- const polyline = L.polyline(coordinates, { color, weight, opacity })
115
+ const polyline = L.polyline(coordinates, { color, weight: 4, opacity: 0.8 })
195
116
  .addTo(routeLayerRef.current!)
196
- .on('click', (e: L.LeafletMouseEvent) => {
197
- L.DomEvent.stopPropagation(e);
198
- setSelectedRouteIndex(index);
199
- routePolylinesRef.current.forEach((pl, i) => {
200
- pl.setStyle({
201
- color: i === index ? 'green' : 'black',
202
- weight: i === index ? 5 : 3,
203
- opacity: i === index ? 1.0 : 0.5,
204
- });
205
- });
206
- const bounds = polyline.getBounds();
207
- const center = bounds.getCenter();
208
- L.popup()
209
- .setLatLng(center)
210
- .setContent(`
211
- <b>Route ${index + 1}</b><br>
212
- Distance: ${route.distance.toFixed(2)} m<br>
213
- Durée: ${(route.duration / 60).toFixed(2)} min<br>
214
- Départ: ${route.startPlaceName || 'Départ'}<br>
215
- Destination: ${route.endPlaceName || 'Destination'}
216
- `)
217
- .openOn(mapRef.current!);
218
- });
219
-
117
+ .on('click', () => setSelectedRouteIndex(index));
220
118
  routePolylinesRef.current.push(polyline);
221
- allCoordinates = [...allCoordinates, ...coordinates];
222
-
223
- if (index === selectedRouteIndex) {
224
- const startPoint = coordinates[0];
225
- const endPoint = coordinates[coordinates.length - 1];
226
- (async () => {
227
- let startPlaceName = route.startPlaceName || 'Départ';
228
- if (route.startPlaceName === 'Votre position') {
229
- const closestStartPlace = await apiClient.findClosestPlace(startPoint[1], startPoint[0]);
230
- startPlaceName = closestStartPlace?.name || route.startPlaceName;
231
- }
232
- L.marker(startPoint).addTo(routeLayerRef.current!).bindPopup(`
233
- <b>${startPlaceName}</b><br>Lat: ${startPoint[0].toFixed(6)}<br>Lng: ${startPoint[1].toFixed(6)}
234
- `);
235
- L.marker(endPoint).addTo(routeLayerRef.current!).bindPopup(`
236
- <b>${route.endPlaceName || 'Destination'}</b><br>Lat: ${endPoint[0].toFixed(6)}<br>Lng: ${endPoint[1].toFixed(6)}
237
- `);
238
- })();
239
- }
119
+ allCoordinates.push(...coordinates);
240
120
  }
241
121
  });
242
122
 
243
- if (allCoordinates.length > 0) {
244
- // Ajuster la vue pour montrer l'itinéraire, mais dans les limites du Cameroun
245
- const routeBounds = L.latLngBounds(allCoordinates);
246
- const paddedBounds = routeBounds.pad(0.1); // Ajouter un peu de marge
247
-
248
- // S'assurer que les bounds ajustées sont dans les limites du Cameroun
249
- const finalBounds = L.latLngBounds(
250
- [
251
- Math.max(paddedBounds.getSouth(), CAMEROON_BOUNDS.getSouth()),
252
- Math.max(paddedBounds.getWest(), CAMEROON_BOUNDS.getWest())
253
- ],
254
- [
255
- Math.min(paddedBounds.getNorth(), CAMEROON_BOUNDS.getNorth()),
256
- Math.min(paddedBounds.getEast(), CAMEROON_BOUNDS.getEast())
257
- ]
258
- );
259
-
260
- mapRef.current!.fitBounds(finalBounds);
261
- }
262
- } else if (searchedPlace && searchedPlace.coordinates) {
263
- centerOnPoint(searchedPlace.coordinates.lat, searchedPlace.coordinates.lng, searchedPlace.name);
264
- } else if (userLocation) {
265
- centerOnPoint(userLocation.latitude, userLocation.longitude, 'Votre position');
266
- } else {
267
- // Retour à la vue par défaut du Cameroun
268
- mapRef.current!.setView([5.5, 12.0], 6, { animate: true });
269
- mapRef.current!.setMaxBounds(CAMEROON_BOUNDS);
123
+ // 🗺 Ajustement intelligent de la vue
124
+ const routeBounds = L.latLngBounds(allCoordinates);
125
+ const mergedBounds = routeBounds.extend(CAMEROON_BOUNDS); // Ne jamais sortir du pays
126
+ mapRef.current.fitBounds(mergedBounds, { padding: [30, 30] });
127
+ }
128
+ else if (!routes?.length) {
129
+ // 🌍 Recentrage sur tout le Cameroun si aucun itinéraire
130
+ mapRef.current.fitBounds(CAMEROON_BOUNDS, { animate: true });
270
131
  }
271
- }, [apiClient, userLocation, searchedPlace, routes, selectedRouteIndex, setSelectedRouteIndex]);
132
+ }, [routes, selectedRouteIndex]);
272
133
 
273
- return <div className="w-full h-screen" ref={mapContainerRef} />;
134
+ return <div ref={mapContainerRef} className="w-full h-screen rounded-xl overflow-hidden shadow-md" />;
274
135
  };
275
136
 
276
- export default MapView;
137
+ export default MapView;