This Lab provides an introduction to basic Interactive mapping techniques using Leaflet and Mapbox. The aim is to provide an overview of techniques that you can use in your own spatial data visualizations. All the mapping software libraries discussed here have good online tutorials where you can explore further mapping examples beyond this lab:
And for a general HTML and JavaScript reference, a good site is:
Submission
Please carefully read the instruction and play with the 6 examples. The zip file with Lab 5 materials can be found here: https://github.com/fuzhen-yin/uccs_cartography/blob/main/lab_materials/lab5.zip. (Don’t know how to download the data? Please read: Lab 4 - Overview)
At the end of the lab, you are required to:
Please submit a zip with two .html files and any supporting documents (e.g., images) to Canvas.
Leaflet is a very popular open source library for online interactive maps. It is lightweight and straightforward to use, and is ideal for simpler mapping sites. The API and documentation for Leaflet.js can be found here
Below is a simple html page to create an interactive map with OpenStreetMap data (same example as last week). You can zoom around and the map layer will update.
The important parts of the code are as follows:
<head>
part of the page, using the <script>
tag.<link>
tag. The stylesheet controls the
layout of different elements, and ensures the map and map controls
appear in the right place on the page.<body>
part of the page using a
<div>
tag to specify the size and location of the map
element, and a <script>
that calls the Leaflet
commands to create the map. A L.map
variable is invoked,
specifying the latitude, longitude and zoom level of
the map in the setview
attributes. Then the
L.tileLayer
command specifies what data will be used as the
background layer, linking to a set of tiles on an online map server.
Here we request the OpenStreetMap raster tiles layer, and add this layer
to the map.
<html>
<head>
<title>Leaflet Example 1</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
<style>
body { margin:0; padding:0; }
#mapdiv { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id="mapdiv"></div>
<script>
var mymap = L.map('mapdiv').setView([38.8928, -104.8036], 16);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a>'
}).addTo(mymap);
</script>
</body>
</html>
Note that in the code we are combining a variable declaration, instantiating the L.map object, and running the setView method in the same statement:
var mymap = L.map('mapdiv').setView([38.8928, -104.8036], 16);
This statement can alternatively be split into two lines, performing the same tasks:
var mymap = L.map('mapdiv');
mymap.setView([38.8928, -104.8036], 16);
Save this file as example1.html.
When you double click on the html file you have created, it should open in your default web browser software, and show a map as the image below.
It’s possible to swap the tileLayer for another raster map layer that you want to use, for example a Carto All Black tilelayer (also created using OpenStreetMap data):
<html>
<head>
<title>Leaflet Example 2</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
<style>
body { margin:0; padding:0; }
#mapdiv { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id="mapdiv"></div>
<script>
var mymap = L.map('mapdiv').setView([38.8928, -104.8036], 16);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', {
maxZoom: 18,
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>'
}).addTo(mymap);
</script>
</body>
</html>
Save this file as example2.html.
When you double click on the html file you have created, it should open in your default web browser software, and show a map as the image below.
So far we have created the background layer to our map. Typically, we
want to add some location data in the foreground. One
simple method of doing this is to hand-code location
data in our script, as the example below shows using the
commands L.marker
, L.circle
and
L.polygon
.
<html>
<head>
<title>Leaflet Example 3</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
<style>
body { margin:0; padding:0; }
#mapdiv { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id="mapdiv"></div>
<script>
var mymap = L.map('mapdiv').setView([38.8928, -104.8036], 16);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', {
maxZoom: 18,
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>'
}).addTo(mymap);
var marker = L.marker([38.898586, -104.805672]).addTo(mymap);
var circle = L.circle([38.889592, -104.791615], {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5,
radius: 200
}).addTo(mymap);
var polygon = L.polygon([
[38.89569833939097, -104.80627386295626],
[38.89186674552239, -104.80462559978713],
[38.89083179638379, -104.79364069793745]
]).addTo(mymap);
</script>
</body>
</html>
Save this file as example3.html.
When you double click on the html file you have created, it should open in your default web browser software, and show a map as the image below.
Now, we add popup interactivity to the map by using the functions
bindPopup
and openPopup
. It follows the same
html syntax when adding hyperlink such as
<a href='https://www.uccs.edu/'>Link to UCCS</a>
.
<html>
<head>
<title>Leaflet Example 4</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
<style>
body { margin:0; padding:0; }
#mapdiv { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id="mapdiv"></div>
<script>
var mymap = L.map('mapdiv').setView([38.8928, -104.8036], 16);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', {
maxZoom: 18,
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>'
}).addTo(mymap);
var marker = L.marker([38.898586, -104.805672]).addTo(mymap);
var circle = L.circle([38.889592, -104.791615], {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5,
radius: 200
}).addTo(mymap);
var polygon = L.polygon([
[38.89569833939097, -104.80627386295626],
[38.89186674552239, -104.80462559978713],
[38.89083179638379, -104.79364069793745]
]).addTo(mymap);
polygon.bindPopup("Hello World! <br> This is the Main Campus of UCCS. <br> <a href='https://www.uccs.edu/'>Link to UCCS</a>").openPopup();
marker.bindPopup("A marker showing the Roaring Fork dining hall")
circle.bindPopup("Here is the UCCS Farm!")
</script>
</body>
</html>
Save this file as example4.html.
When you double click on the html file you have created, it should open in your default web browser software, and show a map as the image below.
Hand-coding location features is not a good way to handle larger datasets. We can add medium sized spatial datasets using the GeoJSON format, a popular text-based format for exchanging vector spatial data in JavaScript Object Notation. See geojson.org for more information.
You can create GeoJSON files easily in QGIS or ArcGIS from any spatial data file (“Export->Save Features As” for QGIS, or “Output to GeoJSON” for ArcGIS ). Alternatively Google “convert to geojson” and you can find a lot of online data converters.
We will discuss importing data files on the web using APIs later in the course. The easiest way to add a GeoJSON file to a Leaflet map is:
to edit the GeoJSON file to create a .js file, and wrap the GeoJSON data inside
var = myvariablename [….];
(see theelpaso_2022_waterbody_area.js
example file included in the lab materials).
To view the elpaso_2022_waterbody_area.js
, right
click and open with any text editors (e.g.,
Brackets, Sublime Text, or Notepad.)
To load an external GeoJSON file without editing, you need to add
some asynchronous data loading functionality to Leaflet, such as the
Leaflet AJAX plugin or using JQuery. The example below loads the file
elpaso_2022_waterbody_area.js
a local file with the address
shown in the code below.
<script src="elpaso_2022_waterbody_area.js"></script>
This example adds some water body data (from the
elpaso_2022_waterbody_area.js
file) on top of our
background map. The water bodies were added using the
L.geoJson
constructor. The function
onEachFeature
runs for each feature, which is styled using
the layer.setStyle
command in the code.
<html>
<head>
<title>Leaflet Example 5</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
<script src="elpaso_2022_waterbody_area.js"></script>
<style>
body { margin:0; padding:0; }
#mapdiv { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id="mapdiv"></div>
<script>
var mymap = L.map('mapdiv').setView([38.859717, -104.801512], 12);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', {
maxZoom: 18,
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>'
}).addTo(mymap);
var water_js = new L.geoJson(water_area,{
onEachFeature: onEachFeature
}).addTo(mymap);
function onEachFeature(feature, layer){
layer.setStyle({
fillColor:'skyblue',
fillOpacity: 0.5,
weight:1,
color:'darkblue',
opacity:1
})
}
</script>
</body>
</html>
Save this file as example5.html.
When you double click on the html file you have created, it should open in your default web browser software, and show a map as the image below.
The GeoJSON approach will work for relatively
small spatial data files of a few megabytes. When your
files get larger then this text based approach will not scale and the
website performance will be slow. You will need to use a different
scalable approach like vector tiles,
so that the spatial data is selected depending on the location and zoom
level that the user is viewing.
If you want to add interactivity and further features to your Leaflet map, then you can follow the online tutorials here: https://leafletjs.com/examples.html
JTW_GB_MSOAflows_2011_50plus.zip
downloaded from Lab
5 materialsThere will be a delay while the file is uploaded and processed into
Mapbox vector tiles. When it is complete, you will get a notification
saying the upload has succeeded, and there will be a new Tileset on the
page with a name like JTW_GB_MSOAflows_2011_50plus-xxx
.
Click on it to see the details.
This
Tileset page has important information such as the Map
ID and the name (which are used to show this
layer in an HTML page using mapbox.gl).
A more advanced way is to use the Mapbox software Tippecanoe to control how features are dropped at low zoom levels, allowing a wider zoom extent.
Now we are going to create a map of the flow data in Mapbox studio. Each map design is called a style in Mapbox. - Click on the Style Editor on the left panel. Then the arrow near New Style button to create a new style using Classic Template.
There are a wide selection of style templates to choose from, mainly using OpenStreetMap (OSM) data. It is interesting to explore these different styles for different projects, with the minimalist Monochrome styles generally the default for data visualizations. For this example, we want to use the Monochrome- Dark style.
You will then be taken to the Mapbox studio interface for designing background mapping. On the left hand side are all the OSM layers, and on the right hand side is the appearance of the map design (just like in GIS software).
JTW_GB_MSOAflows_2011
.When added, the flows layer will appear on the left-hand layers panel. Next we are going to style this layer. Click on the layer itself, the style panel will appear.
You can make many more adjustments to improve your map. For example:
Your final map should appear similar to the map below.
It makes sense to rename the style into something more descriptive than Monochrome’, for example UK_Flow Map. The Publish button at the top right will save your style edits.
Then press the Share button. This includes a Preview URL to view your style. It is better to use the Developer resources to use this map style on your own HTML page.
This is shown in ‘Mapbox_example6.html’. To view your own style, you will need to insert your access token and your Style URL in the example 6 code as shown below. Please submit the .html file of your final stylized flow as part of your Lab 5 assignment.
<html>
<head>
<meta charset="utf-8" />
<title>Mapbox Example 6- UK Flowmap 2011</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v3.10.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v3.10.0/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiZnppbmciLCJhIjoiY2s5eHE0NW4wMDV6aDNnbjFrYWpyNmE1eSJ9.PQHJ-2XYEas7K6CpTJHf0A'; //Mapbox Accesstoken
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/fzing/cm7vgvvn5001l01rhbhmf55np', // stylesheet URL, the style that you've created
center: [-2.855366, 53.273659], // starting position [lng, lat]
zoom: 6 // starting zoom
});
</script>
</body>
</html>
Save this file as example6.html.
When you double click on the html file you have created, it should open in your default web browser software, and show a map as the image below.
Please submit a zip with two .html files and any supporting documents (e.g., images) to Canvas.