7. Create Search Bar and Print Feature

Tutorial: Implementing a Search Feature with React and Leaflet

In this tutorial, we will build a Search component that allows users to search for locations and display the results on a map with a popup containing location information. We will use React, React-Leaflet, and leaflet-geosearch for this component.

1. Import Required Libraries

import React, { useState } from "react";
import { useMap } from "react-leaflet";
import { OpenStreetMapProvider } from "leaflet-geosearch";
import L from "leaflet";

Explanation:

  • useState: React hook for managing local state.
  • useMap: Hook from React-Leaflet to get the map instance.
  • OpenStreetMapProvider: Provider from leaflet-geosearch for geocoding locations based on text.
  • L: Leaflet shorthand for accessing APIs like popup and view settings.

2. Initialize the Search Component

const Search = () => {
const map = useMap();
const [searchText, setSearchText] = useState("");
const [popup, setPopup] = useState(null);
const [suggestions, setSuggestions] = useState([]);
const [isExpanded, setIsExpanded] = useState(false);

Explanation:

  • map: Gets the map instance from useMap.
  • searchText: State to store the user’s search input.
  • popup: State to store the active popup reference on the map.
  • suggestions: State to store location suggestions based on the search text.
  • isExpanded: State to manage the display of the search input field.

3. Handle Search Input Changes

const handleSearchInputChange = (e) => {
const userInput = e.target.value;
setSearchText(userInput);
const provider = new OpenStreetMapProvider();
provider
.search({ query: userInput })
.then((results) => {
const suggestions = results.map((result) => result.label);
setSuggestions(suggestions);
})
.catch((error) => {
console.error("Error fetching search suggestions:", error);
setSuggestions([]);
});
};

Explanation:

  • Updates searchText whenever the user types.
  • Uses OpenStreetMapProvider to fetch location suggestions based on user input.
  • Stores the suggestions in the suggestions state.

4. Handle Clicks on Location Suggestions

const handleSuggestionClick = (suggestion) => {
setSearchText(suggestion);
setSuggestions([]);
};

Explanation:

  • Updates searchText when a user selects a suggestion and clears the suggestions list.

5. Handle Search Form Submission

const handleSearch = async (e) => {
e.preventDefault();
if (!searchText.trim()) return;
const provider = new OpenStreetMapProvider();
const results = await provider.search({ query: searchText });
if (results.length > 0) {
const { x, y, label } = results[0];
const latLng = L.latLng(y, x);
map.setView(latLng, 10);
if (popup) {
popup.removeFrom(map);
}
const newPopup = L.popup()
.setLatLng(latLng)
.setContent(
`<b>${label}</b><br>Latitude: ${y.toFixed(6)}, Longitude: ${x.toFixed(6)}`
)
.openOn(map);
setPopup(newPopup);
}
};

Explanation:

  • Searches for the location based on the input text when the form is submitted.
  • If a location is found, updates the map view to the location and displays a popup with location information.

6. Clear Search Input

const clearInput = () => {
setSearchText('');
setIsExpanded(false);
};

Explanation:

  • Clears the search input and resets the input field to its default state.

7. Render the Search Component

return (
<form onSubmit={handleSearch} onMouseEnter={() => setIsExpanded(true)}
onMouseLeave={() => setIsExpanded(searchText !== '')} style={{
position: "absolute",
top: "1%",
left: "94%",
transform: "translate(-50%, 0)",
zIndex: 1000,
}}>
<input
className="srch"
type="text"
value={searchText}
onChange={handleSearchInputChange}
list="searchSuggestions"
placeholder="Search..."
required
/>

<datalist id="searchSuggestions">
{suggestions.map((suggestion, index) => (
<option key={index} value={suggestion} />
))}
</datalist>
<button type="submit" className="fa fa-search"></button>
<a
href="#"
onClick={clearInput}
className={isExpanded ? "clear-link visible" : "clear-link"}
>


</a>
</form>

);
};

Explanation:

  • Creates a search form with a text input, location suggestions, a submit button, and a clear button.
  • Uses inline CSS to position the form over the map.

8. Export the Component

export default Search;

Explanation:

  • Exports the Search component for use in other parts of the application.

This tutorial outlines how to build a location search feature using React and Leaflet, including fetching location data, showing suggestions, and updating the map with search results.

read more

Tutorial: Capturing and Printing Map Images with React

In this tutorial, we’ll create a PrintLayer component that allows users to capture an image of the map and save it as a PNG file. This component uses html-to-image to convert a portion of the application into an image.

1. Import Required Libraries and Components

import logo from "../Logo/Printer.png";
import { Map } from "../Map/Map";
import React, { useState, useRef, useCallback } from "react";
import { toPng } from "html-to-image";

Explanation:

  • logo: The logo image used for the print button.
  • Map: The map component that will be captured.
  • useState, useRef, useCallback: React hooks for state management, references, and callbacks.
  • toPng: A function from html-to-image to convert HTML elements to PNG images.

2. Initialize State and References

export const PrintLayer = () => {
const [hideComponents, setHideComponents] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const mapRef = useRef();
const setMapRef = useCallback((node) => {
if (node !== null) {
mapRef.current = node;
}
}, []);

Explanation:

  • hideComponents: State to hide elements before capturing.
  • isLoading: State to show a loading message during the capture process.
  • mapRef: A reference for the map element that will be captured.
  • setMapRef: A callback to set the map reference.

3. Function to Capture Image

const handleCapture = () => {
setHideComponents(true); // Hide elements before capture
setIsLoading(true); // Show loading message
setTimeout(() => {
if (mapRef.current === null) {
return;
}
// Hide loading message before capture
setIsLoading(false);
setTimeout(() => {
toPng(mapRef.current)
.then((dataUrl) => {
// Save as image
const link = document.createElement("a");
link.href = dataUrl;
link.download = "map.png";
link.click();
setHideComponents(false); // Show elements after capture
})
.catch((error) => {
console.error("Oops, something went wrong!", error);
setHideComponents(false); // Show elements after an error
});
}, 100); // Short delay to ensure loading message is hidden
}, 1000); // Delay to ensure components are hidden
};

Explanation:

  • handleCapture: Function to hide elements, show the loading message, and capture the map image. The image is then saved as a PNG file and downloaded.

4. Function to Trigger Capture

const toggleForm = () => {
handleCapture(); // Immediately capture when the button is clicked
};

Explanation:

  • toggleForm: Function that calls handleCapture when the print button is clicked.

5. Render the PrintLayer Component

return (
<div>
<button
style={{
position: "absolute",
top: "10%",
right: "28px",
border: "3px solid white",
background: "rgba(255, 255, 255)",
padding: "20px",
borderRadius: "100px",
zIndex: 1000,
backgroundImage: `url(${logo})`,
backgroundRepeat: "no-repeat",
backgroundSize: "30px",
backgroundPosition: "center",
cursor: "pointer",
transition: "transform 0.3s ease-out",
}}
onClick={toggleForm}
onMouseEnter={(e) =>
{
e.target.style.transform = "scale(1.1)";
}}
onMouseLeave={(e) => {
e.target.style.transform = "scale(1)";
}}
></button>
<div ref={setMapRef} style={{ position: "relative" }}>
<Map hideComponents={hideComponents} />
{isLoading && (
<div
style={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
background: "rgba(255, 255, 255, 0.8)",
padding: "20px",
borderRadius: "8px",
zIndex: 1000,
}}
>

Loading...
</div>
)}
</div>
</div>

);

Explanation:

  • A print button positioned at the top-right corner with hover animation.
  • The map area to be captured, with a loading message displayed during the capture process.

6. Export the Component

export default PrintLayer;

Explanation:

  • Exporting the PrintLayer component so it can be used elsewhere in the application.