The traditional way of setting up a React app is to use create-react-app. React is a great frontend Framework for using Geoman and Leaflet and we will show you how to get started by setting up the scaffolding. If you just want to dive in, you can jump straight to our GitHub repo for the code.
You can use create-react-app with the JavaScript package managers like NPX, NPM and Yarn. Here we use NPX and set up a React app project by opening a terminal and running:
npx create-react-app geoman-create-react-app --template typescript
This will create the initial scaffolding for our React app. The
--template typescript
flag insures that we use TypeScript in our app.
Now that we have set up our React app project, we need to install Leaflet and Geoman.
npm i @geoman-io/leaflet-geoman-free leaflet react-leaflet
npm install -D @types/leaflet
After installing the libraries, we can implement the business logic for our app. We will create two components, one for adding the Geoman controls to our map and one for listening to events.
We start by setting up the Geoman Control component which adds the Geoman functionality to our Leaflet map.
src/components/GeomanControl.tsx
import { createControlComponent } from "@react-leaflet/core";
import * as L from "leaflet";
import "@geoman-io/leaflet-geoman-free";
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
interface Props extends L.ControlOptions {
position: L.ControlPosition;
drawCircle?: boolean;
oneBlock?: boolean;
}
const Geoman = L.Control.extend({
options: {},
initialize(options: Props) {
L.setOptions(this, options);
},
addTo(map: L.Map) {
if (!map.pm) return;
map.pm.addControls({
...this.options,
});
},
});
const createGeomanInstance = (props: Props) => {
return new Geoman(props);
};
export const GeomanControl = createControlComponent(createGeomanInstance);
Next, we need the Event Listener component and create a file
src/components/Events.tsx
. This component integrates with our Leaflet map
using React Leaflet and adds various event listeners to handle different
interactions like creation and editing of map layers.
src/components/Events.tsx
import { useEffect } from "react";
import { useMap } from "react-leaflet";
const Events = () => {
const map = useMap();
useEffect(() => {
if (map) {
map.on("pm:create", (e) => {
console.log("Layer created:", e);
e.layer.on("click", () => {
console.log("Layer clicked", e);
});
e.layer.on("pm:edit", () => {
console.log("Layer edited", e);
});
e.layer.on("pm:update", () => {
console.log("Layer updated", e);
});
e.layer.on("pm:remove", (e) => {
console.log("Layer removed:", e);
});
e.layer.on("pm:dragstart", (e) => {
console.log("Layer dragstart:", e);
});
e.layer.on("pm:dragend", (e) => {
console.log("Layer dragend:", e);
});
});
map.on("pm:drawstart", (e) => {
console.log("Layer drawstart:", e);
});
map.on("pm:drawend", (e) => {
console.log("Layer drawend:", e);
});
map.on("pm:globaldrawmodetoggled", (e) => {
console.log("Layer globaldrawmodetoggled:", e);
});
map.on("pm:globaldragmodetoggled", (e) => {
console.log("Layer globaldragmodetoggled:", e);
});
map.on("pm:globalremovalmodetoggled", (e) => {
console.log("Layer globalremovalmodetoggled:", e);
});
map.on("pm:globalcutmodetoggled", (e) => {
console.log("Layer globalcutmodetoggled:", e);
});
map.on("pm:globalrotatemodetoggled", (e) => {
console.log("Layer globalrotatemodetoggled:", e);
});
}
}, [map]);
return null;
};
export default Events;
We can now integrate these two components in our React app.
We rewrite the App.tsx
logic to include our components and to display a
Leaflet map.
src/App.tsx
import { MapContainer, TileLayer } from "react-leaflet";
import { GeomanControl } from "./component/GeomanControl";
import Events from "./component/Events";
const App = () => {
return (
<MapContainer
center={[51.505, -0.09]}
zoom={13}
scrollWheelZoom={true}
style={{ width: "100vw", height: "100vh" }}
>
<TileLayer
attribution='<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>'
url="https://api.maptiler.com/maps/streets-v2/256/{z}/{x}/{y}.png?key=FTejVijNkqKWPbQui8i9"
/>
<GeomanControl position="topleft" oneBlock />
<Events />
</MapContainer>
);
};
export default App;
We need to include the Leaflet and Geoman CSS in our HTML head tag in order for the map to display properly.
public/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""
/>
<link
rel="stylesheet"
href="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.css"
/>
<script
src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""
></script>
<script src="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
With these edits we now have used create-react-app to create a React app that
displays a Leaflet map with the Geoman controls. Running npm start
spins up a
server:
You can visit GitHub repo to see the full code and other starter kits for TypeScript Apps with Geoman.
If you have an interesting example of how you have used Geoman and React, we invite you to share it on our GitHub Repo.