@navigoo/map-components 1.0.3 → 1.0.4
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 +100 -10
package/package.json
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { useEffect, useRef } from 'react';
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
2
2
|
import L from 'leaflet';
|
3
3
|
import 'leaflet/dist/leaflet.css';
|
4
4
|
import { parse } from 'wellknown';
|
@@ -28,6 +28,77 @@ const MapView: React.FC<MapViewProps> = ({
|
|
28
28
|
const routeLayerRef = useRef<L.LayerGroup | null>(null);
|
29
29
|
const clickMarkerRef = useRef<L.Marker | null>(null);
|
30
30
|
const routePolylinesRef = useRef<L.Polyline[]>([]);
|
31
|
+
const [ipLocation, setIpLocation] = useState<{ lat: number; lng: number } | null>(null);
|
32
|
+
|
33
|
+
// Fonction pour obtenir la localisation par IP
|
34
|
+
const getLocationByIP = async (): Promise<{ lat: number; lng: number } | null> => {
|
35
|
+
try {
|
36
|
+
const response = await fetch('https://ipapi.co/json/');
|
37
|
+
const data = await response.json();
|
38
|
+
|
39
|
+
if (data.latitude && data.longitude) {
|
40
|
+
return {
|
41
|
+
lat: data.latitude,
|
42
|
+
lng: data.longitude
|
43
|
+
};
|
44
|
+
}
|
45
|
+
return null;
|
46
|
+
} catch (error) {
|
47
|
+
console.error('Erreur de géolocalisation par IP:', error);
|
48
|
+
return null;
|
49
|
+
}
|
50
|
+
};
|
51
|
+
|
52
|
+
// Fonction pour obtenir la localisation par le navigateur
|
53
|
+
const getBrowserLocation = (): Promise<{ lat: number; lng: number }> => {
|
54
|
+
return new Promise((resolve, reject) => {
|
55
|
+
if (!navigator.geolocation) {
|
56
|
+
reject(new Error('Géolocalisation non supportée'));
|
57
|
+
return;
|
58
|
+
}
|
59
|
+
|
60
|
+
navigator.geolocation.getCurrentPosition(
|
61
|
+
(position) => {
|
62
|
+
resolve({
|
63
|
+
lat: position.coords.latitude,
|
64
|
+
lng: position.coords.longitude
|
65
|
+
});
|
66
|
+
},
|
67
|
+
(error) => {
|
68
|
+
reject(error);
|
69
|
+
},
|
70
|
+
{
|
71
|
+
enableHighAccuracy: true,
|
72
|
+
timeout: 10000,
|
73
|
+
maximumAge: 60000
|
74
|
+
}
|
75
|
+
);
|
76
|
+
});
|
77
|
+
};
|
78
|
+
|
79
|
+
// Effet pour la géolocalisation au démarrage
|
80
|
+
useEffect(() => {
|
81
|
+
const initializeLocation = async () => {
|
82
|
+
try {
|
83
|
+
// Essayer d'abord la géolocalisation du navigateur
|
84
|
+
const browserLocation = await getBrowserLocation();
|
85
|
+
setIpLocation(browserLocation);
|
86
|
+
} catch (browserError) {
|
87
|
+
console.log('Géolocalisation navigateur échouée, tentative par IP...', browserError);
|
88
|
+
|
89
|
+
// Fallback sur la géolocalisation par IP
|
90
|
+
const ipLocation = await getLocationByIP();
|
91
|
+
if (ipLocation) {
|
92
|
+
setIpLocation(ipLocation);
|
93
|
+
} else {
|
94
|
+
// Fallback final sur une position par défaut (centre du monde)
|
95
|
+
setIpLocation({ lat: 20, lng: 0 });
|
96
|
+
}
|
97
|
+
}
|
98
|
+
};
|
99
|
+
|
100
|
+
initializeLocation();
|
101
|
+
}, []);
|
31
102
|
|
32
103
|
const parseWKTLineString = (wkt: string): [number, number][] => {
|
33
104
|
try {
|
@@ -52,18 +123,20 @@ const MapView: React.FC<MapViewProps> = ({
|
|
52
123
|
|
53
124
|
useEffect(() => {
|
54
125
|
if (mapContainerRef.current && !mapRef.current) {
|
126
|
+
// Position par défaut centrée sur le monde, sera mise à jour par la géolocalisation
|
127
|
+
const defaultCenter = ipLocation || { lat: 20, lng: 0 };
|
128
|
+
|
55
129
|
mapRef.current = L.map(mapContainerRef.current, {
|
56
|
-
center: [
|
130
|
+
center: [defaultCenter.lat, defaultCenter.lng],
|
57
131
|
zoom: 12,
|
58
|
-
minZoom:
|
59
|
-
maxZoom:
|
60
|
-
|
61
|
-
maxBoundsViscosity: 1.0,
|
132
|
+
minZoom: 2, // Zoom minimal réduit pour voir le monde entier
|
133
|
+
maxZoom: 18, // Zoom maximal augmenté pour plus de détails
|
134
|
+
// Suppression des limites de la carte
|
62
135
|
});
|
63
136
|
|
64
137
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
65
138
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
66
|
-
maxZoom:
|
139
|
+
maxZoom: 18,
|
67
140
|
}).addTo(mapRef.current);
|
68
141
|
|
69
142
|
L.Icon.Default.mergeOptions({
|
@@ -91,13 +164,26 @@ const MapView: React.FC<MapViewProps> = ({
|
|
91
164
|
});
|
92
165
|
}
|
93
166
|
|
167
|
+
// Mettre à jour le centre de la carte quand la localisation par IP est disponible
|
168
|
+
if (mapRef.current && ipLocation && !userLocation && !searchedPlace && !routes) {
|
169
|
+
mapRef.current.setView([ipLocation.lat, ipLocation.lng], 12, { animate: true });
|
170
|
+
|
171
|
+
// Ajouter un marqueur pour la position détectée
|
172
|
+
if (!markerRef.current) {
|
173
|
+
markerRef.current = L.marker([ipLocation.lat, ipLocation.lng])
|
174
|
+
.addTo(mapRef.current)
|
175
|
+
.bindPopup(`<b>Votre position approximative</b><br>Détectée par IP<br>Lat: ${ipLocation.lat.toFixed(6)}<br>Lng: ${ipLocation.lng.toFixed(6)}`)
|
176
|
+
.openPopup();
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
94
180
|
return () => {
|
95
181
|
if (mapRef.current) {
|
96
182
|
mapRef.current.remove();
|
97
183
|
mapRef.current = null;
|
98
184
|
}
|
99
185
|
};
|
100
|
-
}, [apiClient]);
|
186
|
+
}, [apiClient, ipLocation]);
|
101
187
|
|
102
188
|
useEffect(() => {
|
103
189
|
if (!mapRef.current) return;
|
@@ -190,10 +276,14 @@ const MapView: React.FC<MapViewProps> = ({
|
|
190
276
|
centerOnPoint(searchedPlace.coordinates.lat, searchedPlace.coordinates.lng, searchedPlace.name);
|
191
277
|
} else if (userLocation) {
|
192
278
|
centerOnPoint(userLocation.latitude, userLocation.longitude, 'Votre position');
|
279
|
+
} else if (ipLocation) {
|
280
|
+
// Centrer sur la position IP si aucune autre position n'est disponible
|
281
|
+
centerOnPoint(ipLocation.lat, ipLocation.lng, 'Votre position approximative', 12);
|
193
282
|
} else {
|
194
|
-
|
283
|
+
// Position de fallback centrée sur le monde
|
284
|
+
mapRef.current!.setView([20, 0], 2, { animate: true });
|
195
285
|
}
|
196
|
-
}, [apiClient, userLocation, searchedPlace, routes, selectedRouteIndex, setSelectedRouteIndex]);
|
286
|
+
}, [apiClient, userLocation, searchedPlace, routes, selectedRouteIndex, setSelectedRouteIndex, ipLocation]);
|
197
287
|
|
198
288
|
return <div className="w-full h-screen" ref={mapContainerRef} />;
|
199
289
|
};
|