Spaces:
Runtime error
Runtime error
Commit
·
0bcfa53
1
Parent(s):
f07dae8
Simple geodistancefeature with polyline and distance text rendering
Browse files- Added key near polyline to ensure that distance key changes as the input points change. Using ToolTip for rendering the distance.
- Distance Unit options not yet present
- The polyline that joins two points are just straight lines, not proper curves.
frontend/src/components/Map.js
CHANGED
|
@@ -5,9 +5,12 @@ import { MapContainer, TileLayer,
|
|
| 5 |
useMapEvents,
|
| 6 |
Marker,
|
| 7 |
Popup ,
|
| 8 |
-
useMap
|
|
|
|
|
|
|
| 9 |
} from 'react-leaflet';
|
| 10 |
import L from 'leaflet';
|
|
|
|
| 11 |
import 'leaflet/dist/leaflet.css';
|
| 12 |
|
| 13 |
|
|
@@ -18,11 +21,11 @@ L.Icon.Default.mergeOptions({
|
|
| 18 |
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png',
|
| 19 |
});
|
| 20 |
|
| 21 |
-
const ClickHandler = ({
|
| 22 |
useMapEvents({
|
| 23 |
click(e) {
|
| 24 |
const { lat, lng } = e.latlng;
|
| 25 |
-
|
| 26 |
},
|
| 27 |
});
|
| 28 |
return null;
|
|
@@ -49,6 +52,9 @@ const Map = ( { onMapClick, searchQuery, contentType } ) => {
|
|
| 49 |
const startWidth = useRef(0);
|
| 50 |
const containerRef = useRef(null);
|
| 51 |
|
|
|
|
|
|
|
|
|
|
| 52 |
const handleMouseDown = (e) => {
|
| 53 |
isDragging.current = true;
|
| 54 |
startX.current = e.clientX;
|
|
@@ -163,6 +169,37 @@ const Map = ( { onMapClick, searchQuery, contentType } ) => {
|
|
| 163 |
setWikiWidth(20);
|
| 164 |
};
|
| 165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
return (
|
| 167 |
<div ref={containerRef} style={{ display: 'flex', height: '100vh', width: '100%', overflow: 'hidden' }}>
|
| 168 |
{panelSize !== 'closed' && (
|
|
@@ -241,7 +278,7 @@ const Map = ( { onMapClick, searchQuery, contentType } ) => {
|
|
| 241 |
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
| 242 |
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
| 243 |
/>
|
| 244 |
-
<ClickHandler
|
| 245 |
<Marker position={markerPosition}>
|
| 246 |
{contentType === 'summary' && (
|
| 247 |
<Popup minWidth={250}>
|
|
@@ -256,6 +293,49 @@ const Map = ( { onMapClick, searchQuery, contentType } ) => {
|
|
| 256 |
</Popup>
|
| 257 |
)}
|
| 258 |
</Marker>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
</MapContainer>
|
| 260 |
{panelSize === 'closed' && (
|
| 261 |
<button
|
|
|
|
| 5 |
useMapEvents,
|
| 6 |
Marker,
|
| 7 |
Popup ,
|
| 8 |
+
useMap,
|
| 9 |
+
Polyline,
|
| 10 |
+
Tooltip
|
| 11 |
} from 'react-leaflet';
|
| 12 |
import L from 'leaflet';
|
| 13 |
+
|
| 14 |
import 'leaflet/dist/leaflet.css';
|
| 15 |
|
| 16 |
|
|
|
|
| 21 |
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png',
|
| 22 |
});
|
| 23 |
|
| 24 |
+
const ClickHandler = ({ onClick }) => {
|
| 25 |
useMapEvents({
|
| 26 |
click(e) {
|
| 27 |
const { lat, lng } = e.latlng;
|
| 28 |
+
onClick(lat, lng);
|
| 29 |
},
|
| 30 |
});
|
| 31 |
return null;
|
|
|
|
| 52 |
const startWidth = useRef(0);
|
| 53 |
const containerRef = useRef(null);
|
| 54 |
|
| 55 |
+
const [geoPoints, setGeoPoints] = useState([]);
|
| 56 |
+
const [geoDistance, setGeoDistance] = useState(null);
|
| 57 |
+
|
| 58 |
const handleMouseDown = (e) => {
|
| 59 |
isDragging.current = true;
|
| 60 |
startX.current = e.clientX;
|
|
|
|
| 169 |
setWikiWidth(20);
|
| 170 |
};
|
| 171 |
|
| 172 |
+
const handleGeoClick = useCallback(async (lat, lon) => {
|
| 173 |
+
const updatedPoints = [...geoPoints, { lat, lon }];
|
| 174 |
+
if (updatedPoints.length > 2) {
|
| 175 |
+
updatedPoints.shift(); // keep only two
|
| 176 |
+
}
|
| 177 |
+
setGeoPoints(updatedPoints);
|
| 178 |
+
|
| 179 |
+
if (updatedPoints.length === 2) {
|
| 180 |
+
console.log("Fetching distance");
|
| 181 |
+
try {
|
| 182 |
+
|
| 183 |
+
const res = await fetch(`${BACKEND_URL}/geodistance`, {
|
| 184 |
+
method: 'POST',
|
| 185 |
+
headers: { 'Content-Type': 'application/json' },
|
| 186 |
+
body: JSON.stringify({
|
| 187 |
+
lat1: updatedPoints[0].lat,
|
| 188 |
+
lon1: updatedPoints[0].lon,
|
| 189 |
+
lat2: updatedPoints[1].lat,
|
| 190 |
+
lon2: updatedPoints[1].lon,
|
| 191 |
+
unit: 'km',
|
| 192 |
+
}),
|
| 193 |
+
});
|
| 194 |
+
const data = await res.json();
|
| 195 |
+
setGeoDistance(data.distance);
|
| 196 |
+
} catch (err) {
|
| 197 |
+
console.error('Failed to fetch distance:', err);
|
| 198 |
+
setGeoDistance(null);
|
| 199 |
+
}
|
| 200 |
+
}
|
| 201 |
+
}, [geoPoints]);
|
| 202 |
+
|
| 203 |
return (
|
| 204 |
<div ref={containerRef} style={{ display: 'flex', height: '100vh', width: '100%', overflow: 'hidden' }}>
|
| 205 |
{panelSize !== 'closed' && (
|
|
|
|
| 278 |
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
| 279 |
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
| 280 |
/>
|
| 281 |
+
<ClickHandler onClick={handleGeoClick} />
|
| 282 |
<Marker position={markerPosition}>
|
| 283 |
{contentType === 'summary' && (
|
| 284 |
<Popup minWidth={250}>
|
|
|
|
| 293 |
</Popup>
|
| 294 |
)}
|
| 295 |
</Marker>
|
| 296 |
+
|
| 297 |
+
{geoPoints.map((pt, index) => (
|
| 298 |
+
<Marker key={`geo-${index}`} position={[pt.lat, pt.lon]}>
|
| 299 |
+
<Popup>
|
| 300 |
+
Point {index + 1}: {pt.lat.toFixed(4)}, {pt.lon.toFixed(4)}
|
| 301 |
+
</Popup>
|
| 302 |
+
</Marker>
|
| 303 |
+
))}
|
| 304 |
+
|
| 305 |
+
{/* Polyline if 2 points are selected */}
|
| 306 |
+
{geoPoints.length === 2 && (
|
| 307 |
+
<Polyline
|
| 308 |
+
key={geoPoints.map(pt => `${pt.lat},${pt.lon}`).join('-')}
|
| 309 |
+
positions={[
|
| 310 |
+
[geoPoints[0].lat, geoPoints[0].lon],
|
| 311 |
+
[geoPoints[1].lat, geoPoints[1].lon]
|
| 312 |
+
]}
|
| 313 |
+
pathOptions={{ color: '#1976d2', weight: 4 }}
|
| 314 |
+
>
|
| 315 |
+
{geoDistance !== null && (
|
| 316 |
+
<Tooltip
|
| 317 |
+
direction="center"
|
| 318 |
+
permanent
|
| 319 |
+
offset={[0, 0]}
|
| 320 |
+
opacity={1}
|
| 321 |
+
className="distance-tooltip"
|
| 322 |
+
>
|
| 323 |
+
<span style={{
|
| 324 |
+
color: '#1976d2',
|
| 325 |
+
fontWeight: 600,
|
| 326 |
+
fontSize: '15px',
|
| 327 |
+
background: 'none',
|
| 328 |
+
border: 'none',
|
| 329 |
+
boxShadow: 'none',
|
| 330 |
+
padding: 0
|
| 331 |
+
}}>
|
| 332 |
+
{geoDistance.toFixed(2)} km
|
| 333 |
+
</span>
|
| 334 |
+
</Tooltip>
|
| 335 |
+
)}
|
| 336 |
+
</Polyline>
|
| 337 |
+
)}
|
| 338 |
+
|
| 339 |
</MapContainer>
|
| 340 |
{panelSize === 'closed' && (
|
| 341 |
<button
|