5 MIN READ
   //   Jul 9, 2021

Building interactive maps with Leaflet and React

Sam Philemon

Having a map is a vital tool for engaging with audiences for many online businesses. Interactive maps allow direct interaction with your site visitors. It also responds and anticipates the needs of your users/customers. In this article, we are going to develop a simple interactive map that shows the state and union territory wise Covid-19 cases in India using Leaflet JS and React. 

Let’s get started.


What is Leaflet? 

Leaflet is an open-source JavaScript library for developing interactive maps. Weighing just about 39 KB of JS, it has all the mapping features most developers ever need. It’s a lightweight, open-source mapping library that utilizes OpenStreetMap. It has more than 30k stars on GitHub


Installing React-Leaflet 

We need to install react-leaflet in our React project. Please follow the steps provided in the following guide

Once the react-leaflet is added to our package-JSON file, we need to add a few more things to view our map correctly. 

Now we need to add some CSS to our file to start using the map straight away. You can do that either by including the CSS link tag in your head, or you can simply copy-paste the CSS from the file below directly into your project(index.html):

<link
     rel="stylesheet"
     href="https://unpkg.com/[email protected]/dist/leaflet.css"             
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
     crossorigin=""

We need to set the width and height of the .leaflet-container that the map renders itself into, otherwise it won’t be visible because the div will have a height of 0px:

.leaflet-container {
 width: 100%;
 height: 100vh;
}

Once this is done we are ready to get started. The below code displays the code required to render the Leaflet map in the React App. Here we have imported the MapContainer from react-leaflet (along with some other packages which we’ll use in later stages) and we’ll return it from our App component.

MapContainer component: It initializes the map. We set the center position of the map by adding latitude and longitude along with the default zoom level of the map.

TileLayer component: A tile layer is a set of web-accessible tiles that reside on a server. We have added the URL and attribution to our TileLayer component.

import {React, useState} from 'react'
import './App.css'
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet'
import { Icon } from 'leaflet'
import covidData from './data.json'
import icon1 from './images/covid19.svg'

function App() {
  return (
     <MapContainer center = { [ 20.593683, 78.962883 ] }
         zoom = { 5 }
         scrollWheelZoom = { true }
     >
     <TileLayer
attribution='&copy; <a href="https://stadiamaps.com/">Stadia Maps</a>, &copy; <a href="https://openmaptiles.org/">OpenMapTiles</a> &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors'
       url = 'https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png'
     />
</MapContainer>
)
}


Adding Map Markers

To display the data in our map as markers, first, we need the data source. I have created the data source in a JSON file that contains all the state-wise(and union territories as well) covid details in India. We will load this data locally from a JSON file, but to get an idea how our data looks like, here’s an example:

{
   "Id": 1,
   "Location": "Maharashtra",
   "Total_Cases": "36,39,855",
   "New_Cases_Per_Day": "61,695",
   "Cases_Per_1_Million_People": "31,877",
   "Deaths": "59,153",
   "Latitude": 19.601194,
   "Longitude": 75.552979
 },
 {
   "Id": 2,
   "Location": "Kerala",
   "Total_Cases": "11,97,301",
   "New_Cases_Per_Day": "8,126",
   "Cases_Per_1_Million_People": "34,574",
   "Deaths": "4,856",
   "Latitude": 10.850516,
   "Longitude": 76.27108
 }

Once the data source is created, we can map through the data inside our MapContainer component, which returns a marker component for each of the state-wise data related to covid. A Marker component is used to display clickable/draggable icons on the map. It requires a position property to display the render location on the map. It takes an array of [ latitude, longitude ], the same as the center property in MapContainer.

In addition to this, we have initialized a useState hook with null. Inside the click eventHandler we will set the activeCovid when the user clicks on the marker. It will show the information to the user about the particular selected stated in a map popup. 

function App() {
  const [ activeCovid, setActiveCovid ] = useState( null );
  return (
     <MapContainer center = { [ 20.593683, 78.962883 ] } zoom = { 5 }
{ covidData.map(eachData => (
         <Marker
           key={eachData.Id}
           position= {[eachData.Latitude, eachData.Longitude]}
           eventHandlers={{
             click: () => {
               setActiveCovid(eachData)
             }
           }}
         />
       ))}
     </MapContainer>
)
}


Adding Map Popups

Since we are tracking which state or union territory the user has clicked on, if the data is available for that state or union territory then we can display the Popup. The Popup component will display a white rounded rectangle shape that can be closed, and much like a Marker component, we need to give a position so it will know where to render on the map. Inside the popup, we can pass our HTML to show the total cases, new cases (1-day *), cases per 1 million people for the selected state or union territory. 

There is an onClose property/event on the Popup component. When a user closes the popup it will help us track and update the setActiveCovid state hook accordingly.

<MapContainer center = { [ 20.593683, 78.962883 ] } zoom = { 5 } >
{ activeCovid && (
        <Popup
         position={ [ activeCovid.Latitude, activeCovid.Longitude ] }
         onClose={()=>{
            setActiveCovid(null)
          }}
        >
          <div>
           <h1>{ activeCovid.Location }</h1>
           <p>Total cases:  { activeCovid.Total_Cases }</p>
            <p>New cases (1 day*):  { activeCovid.New_Cases_Per_Day }</p>
       <p>Cases per 1 million people:  { activeCovid.Cases_Per_1_Million_People }</p>
           <p>Deaths:  { activeCovid.Deaths }</p>
         </div>
       </Popup>
     )}

 </MapContainer>


Displaying the Custom Marker Icons

Now we can add our custom icons as well. It is very easy in the leaflet to add our custom icons. First, we need to import the icon from the leaflet itself. With that, we can create a new icon instance by providing the URL location of the image along with its size.

import { Icon } from 'leaflet'
const covidIcon = new Icon({
 iconUrl: icon1,
 iconSize: [25, 25]
})

The Marker component provides an optional property icon that can be set to the covidIcon variable that we created. Once the custom marker is added our website will look like this.


Final Website

Interactive maps with Leaflet and React


Conclusion

In this article, we have learned that React-Leaflet is a great open-source free mapping library alternative to Google Maps and MapBox. It is an extremely easy-to-use package and is extremely lightweight (39KB of JS). We have also demonstrated a small use case where we have displayed the state or union territory wise Covid-19 cases in India using Leaflet-react. Feel free to play around with this code to develop your own interactive maps. And share your experience with us in the comment section below!