Topo Map Viewer Project


Overview
This project is a web application that displays a topographic map centered on the user's current geographic location. It uses the browser's geolocation API to determine the user's position and the Leaflet library (with React integration) to render the map and marker.
Key features
User Location Detection: on load, the app request user's location using the geolocation API. When the permission is granted, it fetches the latitude and longitude
Topographic Map Display: The map is using OpenTopoMap tile services
Marker / Popup: A marker is on the user's current location and a popup indicating the location
Programming Languages / Libraries / Frameworks / Databases Used
React: For building the user interface.
React-leaflet: React bindings for the Leaflet map library.
Leaflet: For interactive maps.
OpenTopoMap: As the map tile provider.
Browser Geolocation API: To get the user's current position.
How does it work (Workflow)?
App Initialization:
The app loads and immediately tries to get the user's location.
Location Handling:
If successful, the map centers on the user's coordinates and displays a marker.
If denied or failed, an error is shown and the map is not displayed.
Map Rendering:
The map is rendered using MapContainer and TileLayer from react-leaflet, with the marker and popup at the user's location.
Icon Fix:
The code includes a fix for missing default marker icons in Leaflet when used with modern build tools.
File Structure (Relevant Parts)
App.jsx: Main React component with map logic.
index.jsx: Entry point, renders the App component.
index.css: (Not shown) Likely contains global styles.
index.html: HTML template with a root div for React.
Unique features of the project
For interactive maps: Leaflet (JavaScript library)
'react-leaflet' is used for integrating Leaflet's mapping capabilities into a modern React application. It also makes the map reactive and component-based.
This project also uses OpenTopoMap tile service which provides detailed topographic information essential for outdoor activities.
import React, { useEffect, useState } from "react";
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import L from "leaflet"
react-leaflet is a React library that provides components for working with interactive maps using Leaflet, a popular open-source JavaScript library for mobile-friendly maps.
What are these components?
MapContainer: The main container for your map. It sets up the map and its view.
TileLayer: This component adds the actual map tiles (the images you see as the map background) from a provider like OpenStreetMap.
Marker: Used to place a marker (like a pin) on the map at a specific location.
Popup: A popup window that can be attached to a marker or a location, usually to display information when clicked.
import "leaflet/dist/leaflet.css" | Loads Leaflet’s default CSS for proper map display
import L from "leaflet" -> This imports the main Leaflet library as the variable L.
You use L to access Leaflet’s core functionality, such as creating custom icons, layers, or other advanced features not directly exposed by react-leaflet.
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
iconRetinaUrl:
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png",
iconUrl:
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png",
shadowUrl:
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png",
});
What this particular snippet does: This deletes _getIconUrl method from the default Leaflet icon prototype.
Why?
In some setups (especially with bundlers like Webpack or Vite), Leaflet’s default way of loading marker images (icons) doesn’t work correctly, because it tries to load them from local files that may not exist in your build output. Deleting this method forces Leaflet to use the URLs you provide in the next step.
L.Icon.Default.mergeOptions({...})
What it does:
This sets new default options for Leaflet’s marker icons.
The options:
iconRetinaUrl: URL for the high-resolution (retina) marker icon.
iconUrl: URL for the standard marker icon.
shadowUrl: URL for the marker’s shadow image.
Why?
By providing explicit URLs (usually from a CDN), you ensure that the marker icons always load correctly, regardless of your build setup.
When is this needed?
When missing marker icons (broken images) on the map.
When using React and bundlers that don’t handle Leaflet’s default image paths.
function App() {
const [position, setPosition] = useState(null);
-> Creates a state variable called position (initially null).
position will eventually hold the user's latitude and longitude.
useEffect(() => {
navigator.geolocation.getCurrentPosition(
(pos) => {
setPosition({
lat: pos.coords.latitude,
lng: pos.coords.longitude,
});
},
(err) => {
console.error("Location error:", err);
alert("Location access is required to view the map.");
}
);
}, []);
->What it does:
Runs once when the component mounts (because of the empty dependency array []).
Uses the browser’s Geolocation API to get the user’s current position.
If successful, updates position with the user's latitude and longitude.
If it fails (e.g., user denies permission), logs the error and shows an alert.
return (
<div>
<h1 style={{ textAlign: "center" }}>🗺️ Topographic Map</h1>
{position ? (
<MapContainer
center={[position.lat, position.lng]}
zoom={13}
style={{ height: "90vh", width: "100%" }}
>
<TileLayer
url="https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png"
attribution='Map data: © <a href="https://opentopomap.org">OpenTopoMap</a>'
/>
<Marker position={[position.lat, position.lng]}>
<Popup>You are here!</Popup>
</Marker>
</MapContainer>
) : (
<p style={{ textAlign: "center" }}>📍 Getting your location...</p>
)}
</div>
);
}