Learning objectives:
At the end of the lesson, learners should be able to:
- Understand how to use Leaflet to display a map with OpenStreetMap tiles.
- Understand how to add markers and cluster them together with MarkerClusterGroup.
- Understand how to fetch and use GeoJSON data to add markers to the map.
- Understand how to change the marker color based on magnitude.
- Understand how to create a legend to indicate the magnitude of the earthquakes.
- Understand how to add a print button to the map.
Overview:
This lesson teaches learners how to use Leaflet, an open-source JavaScript library, to display a map with OpenStreetMap tiles. Learners will also learn how to add markers to the map and cluster them together with MarkerClusterGroup. They will learn how to fetch and use GeoJSON data to add markers to the map and how to change the marker color based on magnitude. Additionally, learners will learn how to create a legend to indicate the magnitude of the earthquakes and how to add a print button to the map. By the end of the lesson, learners will be able to create a map that displays earthquake data for Kyrgyzstan between 2013 and 2023, including a legend that indicates the magnitude of each earthquake and a print button to print the map.
Requirements:
- A code editor such as Visual Studio Code, Sublime Text, Notepad++ or your favorite code editor.
- A web browser such as Google Chrome or Mozilla Firefox
- Basic knowledge of HTML, CSS, and JavaScript
Step 1: Create a new HTML file
We start by creating an HTML file and including the necessary CSS and JavaScript files. In this case, we need to include the Leaflet CSS and JavaScript files, as well as the Marker Cluster CSS and JavaScript files. We will also include our own CSS styles to customize the map.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Leaflet - Intermediate</title>
<!-- Leaflet CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.1/dist/leaflet.css" />
<!-- Marker Cluster CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.1/MarkerCluster.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.1/MarkerCluster.Default.css" />
<style>
#map {
height: 800px;
width: 100%;
}
.map-header {
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%);
background-color: white;
opacity: 0.8;
padding: 10px;
font-size: 24px;
font-weight: bold;
z-index: 9999;
}
.diamond {
width: 0;
height: 0;
border: 10px solid transparent;
border-top-color: currentColor;
transform: rotate(45deg);
}
.legend {
position: absolute;
bottom: 10px;
left: 10px;
background-color: white;
opacity: 0.8;
padding: 10px;
border: 1px solid #ccc;
font-size: 14px;
line-height: 18px;
z-index: 9999;
}
.print-map {
position: absolute;
bottom: 10px;
right: 10px;
z-index: 9999;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="map-header">Kyrgyzstan Earthquakes the Last Decade 2013-2023</div>
<div class="legend">
<p><strong>Magnitude Legend</strong></p>
<div>
<span style="background-color: #32a84e;"> </span> Magnitude less than 2.5
</div>
<div>
<span style="background-color: #8fce00;"> </span> Magnitude between 2.5 and 3.0
</div>
<div>
<span style="background-color: #ffff00;"> </span> Magnitude between 3.0 and 4.0
</div>
<div>
<span style="background-color: #ffa500;"> </span> Magnitude between 4.0 and 5.0
</div>
<div>
<span style="background-color: #cc0000;"> </span> Magnitude greater than 5.0
</div>
</div>
<div class="print-map">
<button onclick="window.print()">Print Map</button>
</div>
<script>
// Leaflet code will go here
</script>
</body>
</html>
This is an HTML code that creates a web page containing a Leaflet map displaying earthquake data for Kyrgyzstan from the last decade (2013-2023). The code imports the necessary CSS files for Leaflet and Marker Cluster. The style section contains CSS rules that define the size and position of the map, header, legend, and print button. The body section contains a div element with the ID “map” which will be used by Leaflet to render the map. It also contains a map header, a legend explaining the magnitude colors, and a print button to print the map. Overall, this HTML code sets up the structure of the web page and defines the CSS styles used to display the Leaflet map and additional content. The next step is to create a JavaScript file that will add interactivity to the map by fetching and displaying the earthquake data.
Step 2: Loading Required Libraries and Initializing Map
1.In this step we will import the Leaflet and Marker Cluster libraries from the web using a Content Delivery Network (CDN). This means that the libraries are not hosted on the local machine, but instead are loaded from the internet.
<!-- Leaflet JavaScript -->
<script src="https://unpkg.com/leaflet@1.9.1/dist/leaflet.js"></script>
<!-- Marker Cluster JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.1/leaflet.markercluster.js"></script>
2.Next, an inline script is used to initialize the map. It creates a new Leaflet map instance, sets its center to [41.2, 74.5]
with a zoom level of 7
, and assigns it to a variable called map
. The third section adds OpenStreetMap tiles to the map. It calls the L.tileLayer()
function with a URL to the OpenStreetMap tile server and adds it to the map using the addTo()
method. The maxZoom
option specifies the highest zoom level available, and the attribution
option adds a link to the OpenStreetMap contributors.
<script>
// Initialize the map
var map = L.map('map').setView([41.2, 74.5], 7);
// Add OpenStreetMap tiles
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: 'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors'
}).addTo(map);
</script>
Step 3: Fetch Earthquake Data and Create Markers with Popup Information
1.Initialize a markers
variable to an instance of L.markerClusterGroup()
, which is a Leaflet plugin that groups markers together in clusters based on their proximity to each other.
var markers = L.markerClusterGroup()
2.Fetch earthquake data from the USGS API by making a fetch()
call to the API endpoint. The endpoint returns a GeoJSON object representing the earthquake data. Once the data is returned from the API, call the json()
method on the response to convert the response body to a JSON object. Once the GeoJSON object is obtained, loop through each feature in the features
array using the forEach()
method.
fetch('https://earthquake.usgs.gov/fdsnws/event/1/query.geojson?starttime=2013-03-05%2000:00:00&endtime=2023-03-12%2023:59:59&maxlatitude=43.232&minlatitude=39.253&maxlongitude=80.354&minlongitude=69.28&minmagnitude=2.5&orderby=time')
.then(response => response.json())
.then(data => {
data.features.forEach(feature => {
// Code to handle each feature goes here
});
3.For each feature, create a new marker with a custom icon that indicates the magnitude of the earthquake. The marker is created using the L.marker()
method, and the icon is set using the icon
option. The divIcon
option allows us to create a custom icon using HTML and CSS.
fetch('https://earthquake.usgs.gov/fdsnws/event/1/query.geojson?starttime=2013-03-05%2000:00:00&endtime=2023-03-12%2023:59:59&maxlatitude=43.232&minlatitude=39.253&maxlongitude=80.354&minlongitude=69.28&minmagnitude=2.5&orderby=time')
.then(response => response.json())
.then(data => {
data.features.forEach(feature => {
// Code to handle each feature goes here
});
4.Set the color of the marker based on the magnitude of the earthquake using a series of conditional statements.
fetch('https://earthquake.usgs.gov/fdsnws/event/1/query.geojson?starttime=2013-03-05%2000:00:00&endtime=2023-03-12%2023:59:59&maxlatitude=43.232&minlatitude=39.253&maxlongitude=80.354&minlongitude=69.28&minmagnitude=2.5&orderby=time')
.then(response => response.json())
.then(data => {
data.features.forEach(feature => {
// Change marker color based on magnitude
var color;
if (feature.properties.mag < 2.5) {
color = 'green';
} else if (feature.properties.mag < 3) {
color = 'light green';
} else if (feature.properties.mag < 4) {
color = 'yellow';
} else if (feature.properties.mag < 5) {
color = 'orange';
} else {
color = 'red';
}
5. For each feature, create a new marker with a custom icon that indicates the magnitude of the earthquake. The marker is created using the L.marker()
method, and the icon is set using the icon
option. The divIcon
option allows us to create a custom icon using HTML and CSS.
var marker = L.marker([feature.geometry.coordinates[1], feature.geometry.coordinates[0]], {
icon: L.divIcon({
className: 'custom-div-icon',
html: "<div style='background-color:" + color + "' class='diamond'></div>",
iconSize: [20, 20],
iconAnchor: [10, 10]
})
});
6. Bind a popup to the marker that displays the magnitude of the earthquake. The toFixed()
method is used to round the magnitude to one decimal place.
marker.bindPopup("<b>Magnitude: </b>" + feature.properties.mag.toFixed(1));
7.Add the marker to the markers
cluster group using the addLayer()
method.
markers.addLayer(marker);
8.After all markers have been added to the markers
cluster group, add the cluster group to the Leaflet map using the addLayer()
method.
map.addLayer(markers);
Step 4: Add Cartographic Elements and Markers
1. Sets the opacity of an element with class “map-header” to 0.8.
// Set the header opacity
var header = document.querySelector('.map-header');
header.style.opacity = '0.8';
2.Creates a Leaflet control object for a legend, and defines a function to add content to the legend when it is added to a Leaflet map. Within the legend function, creates an HTML element using Leaflet’s DOM utilities, adds content to it, and returns the element. This creates a legend that displays images and text describing different earthquake magnitudes.
// Create a legend
var legend = L.control({position: 'bottomleft'});
legend.onAdd = function(map) {
var div = L.DomUtil.create('div', 'info legend');
div.innerHTML += '<p><strong>Magnitude Legend</strong></p>';
div.innerHTML += '<p><img src="https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png" alt="magnitude less than 2.5">Magnitude less than 2.5</p>';
div.innerHTML += '<p><img src="https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-blue.png" alt="magnitude between 2.5 and 3.0">Magnitude between 2.5 and 3.0</p>';
div.innerHTML += '<p><img src="https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x.</p>';
3. Adds a circle to a Leaflet map using latitude, longitude, and accuracy values. The circle is colored blue, has a fill opacity of 0.1, and has a radius equal to the accuracy value.
L.circle([lat, lon], accuracy, {
color: 'blue',
fillOpacity: 0.1,
radius: accuracy
}).addTo(mymap);
4.Adds a popup to the circle, displaying the accuracy value to two decimal places.
L.popup()
.setLatLng([lat, lon])
.setContent("Location accuracy: " + accuracy.toFixed(2) + " meters")
.openOn(mymap);
5.Adds a Leaflet marker to the map at latitude 51.5 and longitude -0.09, using a custom green icon.
L.marker([51.5, -0.09], {icon: greenIcon}).addTo(mymap);
Overall, this code sets the header opacity, creates a legend, adds a circle and popup to display location accuracy, and adds a marker to a Leaflet map.
Step 5: Final step. Save HTML
Finally, the code ends with an HTML element which specifies where the map will be displayed on the web page.
Note that the code also includes comments which explain what each section of code does. These comments are denoted by the //
symbol.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Leaflet - Intermediate</title>
<!-- Leaflet CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.1/dist/leaflet.css" />
<!-- Marker Cluster CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.1/MarkerCluster.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.1/MarkerCluster.Default.css" />
<style>
#map {
height: 800px;
width: 100%;
}
.map-header {
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%);
background-color: white;
opacity: 0.8;
padding: 10px;
font-size: 24px;
font-weight: bold;
z-index: 9999;
}
.diamond {
width: 0;
height: 0;
border: 10px solid transparent;
border-top-color: currentColor;
transform: rotate(45deg);
}
.legend {
position: absolute;
bottom: 10px;
left: 10px;
background-color: white;
opacity: 0.8;
padding: 10px;
border: 1px solid #ccc;
font-size: 14px;
line-height: 18px;
z-index: 9999;
}
.print-map {
position: absolute;
bottom: 10px;
right: 10px;
z-index: 9999;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="map-header">Kyrgyzstan Earthquakes the Last Decade 2013-2023</div>
<div class="legend">
<p><strong>Magnitude Legend</strong></p>
<div>
<span style="background-color: #32a84e;"> </span> Magnitude less than 2.5
</div>
<div>
<span style="background-color: #8fce00;"> </span> Magnitude between 2.5 and 3.0
</div>
<div>
<span style="background-color: #ffff00;"> </span> Magnitude between 3.0 and 4.0
</div>
<div>
<span style="background-color: #ffa500;"> </span> Magnitude between 4.0 and 5.0
</div>
<div>
<span style="background-color: #cc0000;"> </span> Magnitude greater than 5.0
</div>
</div>
<div class="print-map">
<button onclick="window.print()">Print Map</button>
</div>
<!-- Leaflet JavaScript -->
<script src="https://unpkg.com/leaflet@1.9.1/dist/leaflet.js"></script>
<!-- Marker Cluster JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.1/leaflet.markercluster.js"></script>
<script>
// Initialize the map
var map = L.map('map').setView([41.2, 74.5], 7);
// Add OpenStreetMap tiles
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: 'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors'
}).addTo(map);
// Add markers with popup information about magnitude
var markers = L.markerClusterGroup();
fetch('https://earthquake.usgs.gov/fdsnws/event/1/query.geojson?starttime=2013-03-05%2000:00:00&endtime=2023-03-12%2023:59:59&maxlatitude=43.232&minlatitude=39.253&maxlongitude=80.354&minlongitude=69.28&minmagnitude=2.5&orderby=time')
.then(response => response.json())
.then(data => {
data.features.forEach(feature => {
// Change marker color based on magnitude
var color;
if (feature.properties.mag < 2.5) {
color = 'green';
} else if (feature.properties.mag < 3) {
color = 'light green';
} else if (feature.properties.mag < 4) {
color = 'yellow';
} else if (feature.properties.mag < 5) {
color = 'orange';
} else {
color = 'red';
}
var marker = L.marker([feature.geometry.coordinates[1], feature.geometry.coordinates[0]], {icon: L.divIcon({
className: 'custom-div-icon',
html: "<div style='background-color:" + color + "' class='diamond'></div>",
iconSize: [20, 20],
iconAnchor: [10, 10]
})});
marker.bindPopup("<b>Magnitude: </b>" + feature.properties.mag.toFixed(1));
markers.addLayer(marker);
});
map.addLayer(markers);
});
// Set the header opacity
var header = document.querySelector('.map-header');
header.style.opacity = '0.8';
// Create a legend
var legend = L.control({position: 'bottomleft'});
legend.onAdd = function(map) {
var div = L.DomUtil.create('div', 'info legend');
div.innerHTML += '<p><strong>Magnitude Legend</strong></p>';
div.innerHTML += '<p><img src="https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png" alt="magnitude less than 2.5">Magnitude less than 2.5</p>';
div.innerHTML += '<p><img src="https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-blue.png" alt="magnitude between 2.5 and 3.0">Magnitude between 2.5 and 3.0</p>';
div.innerHTML += '<p><img src="https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x.</p>';
// Add a circle to the map to show the accuracy of the location
L.circle([lat, lon], accuracy, {
color: 'blue',
fillOpacity: 0.1,
radius: accuracy
}).addTo(mymap);
// Add a popup to the circle to show the accuracy value
L.popup()
.setLatLng([lat, lon])
.setContent("Location accuracy: " + accuracy.toFixed(2) + " meters")
.openOn(mymap);
}
// Add the marker to the map
L.marker([51.5, -0.09], {icon: greenIcon}).addTo(mymap);
</script>
</body>
</html>
Conclusion:
In this lesson, we learned how to use Leaflet to create a map and display markers for earthquake data. We also learned how to use marker clustering to group nearby markers for improved performance. To display information about the magnitude of each earthquake, we used different colors for each magnitude range and created a legend to explain the color scheme. Additionally, we added a header to the map and a button to print the map. For learners, this code provides a foundation for creating interactive maps and customizing the appearance of markers and legends. Learners can experiment with different data sources, marker styles, and map features to create their own custom maps.
Some of the key concepts covered in this lesson include:
- Uses Leaflet library to create an interactive map.
- Fetches earthquake data from USGS API.
- Utilizes marker clustering for better performance.
- Displays markers with different colors based on earthquake magnitude.
- Includes a legend to explain the color coding.
- Provides a “Print Map” button for printing the map.
By following the examples and code provided in this lesson, learners will have a basic understanding of how to use Leaflet to create interactive maps for their web projects. For more information and examples, check out the Leaflet documentation and community resources.
- Leaflet documentation: https://leafletjs.com/
- Leaflet documentation on markers: https://leafletjs.com/examples/custom-icons/
- Leaflet documentation using GeoJSON with Leaflet: https://leafletjs.com/examples/geojson/
- Leaflet documentation interactive Choropleth Map: https://leafletjs.com/examples/choropleth/
- Leaflet Sample: https://leafletjs.com/examples.html
- Leaflet providers preview: Leaflet-providers pr