Updated for Leaflet 1.6.0!!!
In this tutorial, we will use basic HTML, CSS, and JavaScript (specifically, the Leaflet JavaScript library) to create a series of progressively complex web maps.
HTML (HyperText Markup Language) allows us to structure content for our web page. Our map will be contained in an element within an HTML file.
CSS (Cascading Style Sheets) gives us control of the style and visual presentation of our web page. We will use it in the placement and sizing of the map and to customize some Leaflet elements.
JS (JavaScript) gives us the ability to add interactivity to our web page. We will use it to pull in map tiles to our web page, add data (or content layers), and handle user interaction with the map.
Leaflet is an open-source JavaScript library that gives us code to create interactive, mobile friendly web maps. Think of it as a collection (or library) of prewritten JavaScript that does some of the heavy lifting/scripting of web map stuff for us. We will interact with the library through its well documented API. It has a small file size but is packed with useful features and can be extended even further with plugins.
For this guide you will need:
Here is the base map we'll build first:
view example
Open a file editor > Create a new file > Save the file using a .html extension.
Next, set up the structure of the web page by adding the following markup to the file:
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Web Map</title>
<style>
</style>
</head>
<body>
<script>
</script>
</body>
</html>
To make use of Leaflet we need to reference its CSS and JavaScript files in the HTML file.
You can reference the hosted Leaflet files or download copies, host them locally, and reference those. Let's reference the hosted files. To do so, insert the following code into the <head> section of the HTML page:
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin=""
/>
<script
src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
crossorigin=""
></script>
Leaflet requires a <div> element to contain the map and that that <div> element have a set height.
Create a <div> element with the id of "map" to contain the map by adding the following to the HTML <body>:
<div id="map"></div>
To create a map that is 960 px by 500 px add the following CSS code between the <style> tags in the <head> section of the HTML page:
#map {
width: 960px;
height: 500px;
}
Now the HTML and CSS are set. The basic structure and style of our web page is in place. All we need to do is add some JavaScript and we'll have a web map!
The first script we will write pulls in some map tiles and configures a few basic map settings.
Enter the following JavaScript between the <script> tags of the HTML file.
<script>
var map = L.map('map',{
center: [43.64701, -79.39425],
zoom: 15
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
</script>
The code is now complete so the file should now look like this:
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Web Map</title>
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin=""
/>
<script
src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
crossorigin=""
></script>
<style>
#map {
width: 960px;
height:500px;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var map = L.map('map',{
center: [43.64701, -79.39425],
zoom: 15
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
</script>
</body>
</html>
Here is breakdown of the script:
The script creates the 'map' variable, assigns it a new L.map object and passes it the id (‘map’ in this case) of the div element in which the map is to be contained. The script goes on to pass some options that set an initial center point and zoom level for the map. Essentially, this creates a map on the page that we can manipulate.
Next, the script creates a new L.tileLayer object, specifying a particular set of tiles to be loaded into the map container and passes in an 'attribution' option. In this case OpenStreetMap tiles are used but there are many map tile providers. Experiment with different sets and remember to always properly attribute the data and imagery used! As tiles are the basis of web maps, it is worth learning more about them. For detailed information see Anatomy of a Web Map, by Alan McConchie and Beth Schechter of Maptime and Stamen.
Finally, the addTo() method is used to add the tile layer to the map.
Make sure to save the file and then open it with a web browser.
You should see a web map centered on the Mozilla Toronto offices!
Let's go ahead and make two minor adjustments to the script. The map will look the same but be a little more user friendly. The code will be sleeker as well.
view example
<script>
var map = L.map('map',{scrollWheelZoom:false}).setView([43.64701, -79.39425], 15);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
</script>
First, remove the 'center' and 'zoom' options from the L.map constructor.
Next, modify the script to deactivate the scrollWheelZoom interactivity option so that we don't accidentally zoom the map when we are trying to scroll down the page. This is done by passing 'scrollWheelZoom: false' as an option to L.map(). This can be a particularly important usability issue if the map is large or if there is content above and/or below it.
Finally, set the initial center and zoom level with the setView() method.
The map should look just like our first one but we can't control the zoom level by scrolling and the code is a bit streamlined.
Now we have a customized base map with which to build on.
This example adds a Web Map Service (WMS) Weather Overlay to the map.
view example
<script>
var map = L.map('map').setView([43.64701, -79.39425], 3);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
L.tileLayer.wms("https://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", {
layers: 'nexrad-n0r-900913',
format: 'image/png',
transparent: true,
attribution: "Weather data © 2012 IEM Nexrad"
}).addTo(map);
</script>
This code changes the zoom level in the setView() method to 3 and using L.tileLayer.wms() displays a WMS service as a tile layer on the map. Like the L.tilelayer() function, L.tilelayer.wms() is passed the url to the service provider and a set of options.
This example adds a default Leaflet marker on the Mozilla Toronto offices.
view example
<script>
var map = L.map('map', {scrollWheelZoom:false}).setView([43.64701, -79.39425], 15);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
var marker = L.marker([43.64701, -79.39425]).addTo(map);
</script>
This code creates a marker variable and assigns it a marker object with a particular point using L.marker(). The marker is then added to the map with the addTo() method.
This example adds a custom marker (a Firefox icon) on the Mozilla Toronto offices.
view example
<script>
var map = L.map('map', {scrollWheelZoom:false}).setView([43.64701, -79.39425], 15);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
var firefoxIcon = L.icon({
iconUrl: 'https://joshuafrazier.info/images/firefox.svg',
iconSize: [38, 95], // size of the icon
});
var marker = L.marker([43.64701, -79.39425], {icon: firefoxIcon}).addTo(map);
</script>
This code creates the ‘firefoxIcon’ variable and assigns it an icon marker using L.icon().
A few options are passed to L.icon():
This example adds a standard popup to the custom marker. It is activated upon click.
view example
<script>
var map = L.map('map', {scrollWheelZoom:false}).setView([43.64701, -79.39425], 15);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
var firefoxIcon = L.icon({
iconUrl: 'https://joshuafrazier.info/images/firefox.svg',
iconSize: [38, 95], // size of the icon
});
L.marker([43.64701, -79.39425], {icon: firefoxIcon}).bindPopup('Mozilla Toronto Office').addTo(map);
</script>
This code adds a popup to marker click by using the bindPopup() method.
This example adds HTML content and a custom style to the popup.
view example
<style>
#map {
width: 960px;
height:500px;
}
.custom .leaflet-popup-tip,
.custom .leaflet-popup-content-wrapper {
background: #e93434;
color: #ffffff;
}
</style>
This CSS code is added to the head of the HTML file. It adds styles for the class 'custom' which we will create in our script.
<script>
var map = L.map('map', {scrollWheelZoom:false}).setView([43.64701, -79.39425], 15);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
var firefoxIcon = L.icon({
iconUrl: 'https://joshuafrazier.info/images/firefox.svg',
iconSize: [38, 95], // size of the icon
popupAnchor: [0,-15]
});
var customPopup = "Mozilla Toronto Offices<br/>
<img src='https://joshuafrazier.info/images/maptime.gif' alt='maptime logo gif' width='350px'/>";
var customOptions =
{
'maxWidth': '500',
'className' : 'custom'
}
L.marker([43.64701, -79.39425], {icon: firefoxIcon}).bindPopup(customPopup,customOptions).addTo(map);
</script>
This code first adds a 'popupAnchor' option to the icon. The values set moves the popup higher so that more of the icon is visible.
Then it creates the variable ‘customPopup’ and assigns it some HTML content.
Next it creates the variable ‘customOptions’ and specifies a few options:
The bindPopup method takes HTML content and options as arguments. The variables created are passed into the method.
*Note, by default the maximum width of a popup is set to 300px. Sometimes you might want it wider, particularly if you want to add content to it that is larger than 300px. To avoid content spilling out of the popup, make sure the 'maxWidth' option of the popup is set larger than the width of content used.
Examples of how to easily add vector layers to a map:
One of the great things about Leaflet is that there are so many resources out there for you to consult. I perused all of the following to prepare this tutorial for MaptimeTO. Make sure to take advantage of them. And a special big ups to all the fellow Maptimers on this list from whose work I built on and around!
Anatomy of a Web Map, by Alan McConchie and Beth Schechter of Maptime and Stamen.
Leaflet tutorials on the official Leaflet website.
Leaflet.js Essentials, a book by Paul Crickard III.
Leaflet and Mapbox JavaScript API Fundamentals, a presentation by Mapbox's Rafa Gutierrez.
Leaflet Intro, a Maptime PDX presentation by Lyzi Diamond.
Leaflet Tutorial, written for Maptime Boston by Andy Woodruff, Ryan Mullins, and Cristen Jones. It gets into some more advanced techniques such as incorporating jQuery, external geojson files and the Leaflet.markercluster plugin into a project.
Leaflet.JS Introduction, by Thierry Nicola for JS Luxembourg.
Leaflet provider map, an open source Leaflet extension that contains configurations for various free tile providers.
Mapbox Guides and examples are great for learning about web maps in general in addition to Mapbox GL JS, which integrates well with Leaflet.
Find a mistake? Submit an Issue on Github!Back to Top