Tutorials: HTML/CSS/JS | Leaflet | D3 | Visualizing spatial-temporal data 1 | Visualizing spatial-temporal data 2

Interactive Mapping

Tutorial 2. Leaflet

Ningchuan Xiao

Leaflet is an open source JavaScript library for displaying map data in web browsers. Its official web site is http://leafletjs.com. The stable version is 0.7.7, but I have been using the newer version of 1.0.0-rc3 without any problems. We don't need to download the package to use it -- as we know already we can just link to the source to import it into our web page. However, it may be a good idea to actually download the package into our own server.

Set up the web page

Let's write a simple HTML file and called it firstmap.html.

<!DOCTYPE html> <html> <head> <!-- <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.0-rc.3/dist/leaflet.css" /> <script src="https://unpkg.com/leaflet@1.0.0-rc.3/dist/leaflet.js"></script> --> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css" integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ==" crossorigin=""/> <!-- Make sure you put this AFTER Leaflet's CSS --> <script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js" integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ==" crossorigin=""></script> <style> html, body, #map { height: 100%; } body { padding: 0; margin: 0 } </style> </head> <body> <div id="map"></div> <script src="mapping.js"></script> </body> </html>

Using Leaflet

The following goes to a Javascript file called mapping.js and is stored in the same folder as firstmap.html.

var map = L.map('map'); // create a map in the "map" div map.setView([40, -83], 5); // set the view to central Ohio and zoom // create an OpenStreetMap tile layer var osmMapnik = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a>contributors' }); // create another layer using the cartodb service var cartoLight = L.tileLayer("https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png", { attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="https://cartodb.com/attributions">CartoDB</a>' }); var baseMaps = { "Street map light": cartoLight, "OpenStreetMap": osmMapnik }; var layersControl = new L.Control.Layers(baseMaps, null, {collapsed: true, position: 'bottomleft'}); map.addControl(layersControl); map.addLayer(cartoLight, true); // TODO 1 // TODO 2 // TODO 3

Adding GeoJSON files to the map

Now we got a map in the web browser. This is nice and relatively simple. However, it will be much better if we can use our own data to do this. Now, it is time to get a few geospatial datasets and put them on the map.

We are going to download data sets from two sources: the US Census Bureau at http://www.census.gov/geo/maps-data/data/cbf/cbf_counties.html and the then National Atlas, now a part of the National Map at http://nationalmap.gov/small_scale/atlasftp.html. We need 3 data sets, for point, line, and areal phenomena, respectively. Here we demonstrate using these data:

Leaflet has a convenient function to load geojson data into a layer (see here. But here is a problem: leaflet itself does not directly load the file -- it only takes the actual data in geojson format. Our data sets are saved in files, as is commonly the case, and we need to first load the files into and then convert whatever in the file into a Javascript object as in geojson.

We are going to use another Javascript library, a VERY powerful one, called d3.js to do the trick. This is of course a library that does more than just loading files (we will use it to visualize our data later), but loading files is a great feature that comes from this package.

We will put the file cb_2015_us_county_20m.geojson in a folder called data under the folder where we have the html files.

To do this, we must first import the library into our web application by adding the following line to the head of the firstmap.html file:

<script src="https://d3js.org/d3.v7.min.js"></script>

And then we insert the following code to underneath the line marked as TODO 1 in the mapping.js file. The first line of the code uses a D3 technique called fetch to load the data from a JSON file and then use call back function to render it.

d3.json("data/cb_2015_us_county_20m.geojson").then(function(data) { var county_layer = L.geoJson(data, { style: function (feature) { return { color: "#777", fillColor: "#DDD", opacity: 1, fillOpacity: 0.4, weight: 1 }; }, onEachFeature: function(feature, layer) { // TODO 1.1 } }).addTo(map); layersControl.addOverlay(county_layer, "US Counties"); });

The above code may not "work" due to a security policy of many web browsers called CORS (Cross-Origin Resource Sharing). This can be fixed by putting all the files on a HTTP server. There are many ways to set a server, and a quick fix is to use Python. In a terminal, make sure we are in the folder where the html files are stored and run the following command:

python -m http.server

Then enter the following URL in the web browser:

http://0.0.0.0:8000/

This should list all the files in the folder and clicking on firstmap.html will bring up the correct web page.

Now we have it, not only the web page and the map, but also running on a server!

Adding interactivity to the map

We are going to add some fundamental interactivity features to the map by inserting the following to to underneath the line marked as TODO 1.1 in the above code.

layer.on({ mouseover: function(e) { var layer = e.target; layer.setStyle({ weight: 5, color: '#999', fillOpacity: 0.7 }); }, mouseout: function(e) { county_layer.resetStyle(e.target); }, click: function(e) { county_layer.bindPopup("<h2>County</h2><p>This is a " + feature.geometry.type + " with a name of <b>" + feature.properties.NAME + "</b>.</p>"); } });

TODO

Now we have got one overlay layer on the map. It is time to make sure the other two layers are added to the map too.