In the last session, we examined how Folium enabled us to generate web maps relatively quickly and easily using Python – without needing to learn any HTML or JavaScript. The tradeoff, however, was that our web maps were restricted to just what Rob Story (who wrote Folium) had coded to translate Python functions into Leaflet.js
functions. Still, Folium gave us a useful preview of what web maps are and a bit on what they can do.
In this session, we expand on what web maps can do. This time, however, we do delve into the HTML and JavaScript required to access the full functionality of web map. Yes, it’s another coding environment, but it’s not really as complex as you might think at first, particularly because we are going to dive in gently and also because ESRI has provided a useful adaptor to the Leaflet.js
library that simplifies what we need to know – without really restricting any of the capabilities of Leaflet! In fact, ESRI provides some really good tutorials that provides a great introduction to creating web maps.
So, our objectives today will be similar to those of last session where we got started learning Folium (and learned a bit about the bigger picture of web mapping en route). Here we walk through a few example web map documents, from simple to more complex, and get a feel for their structure. We’ll modify some code to determine which map elements are controlled by what lines, simultaneously familiarizing ourselves with the documentation.
In the end, we won’t quite know how to control every last feature in a Leaflet.js
based web map, but we will be able to create some cool maps that not only show data, but allow us to interact with the data beyond what Folium enabled us to do. We’ll also learn a bit about geospatial web services, which itself is a bit of a game changer. But most importantly, of course, we’ll learn that mastering these technologies doesn’t require a computer science degree – just a bit of patience, curiosity, and determination.
The ESRI Leaflet
project is, like Leaflet itself, a JavaScript library that facilitates creating web maps. ESRI Leaflet
actually adds functionality to Leaflet, streamlining the process for using data hosted on ESRI servers (both ArcGIS Online and on individual servers) within web maps. In light of the fact that there is a great deal more data shared as ArcGIS services than as GeoJSON features, it’s a pretty potent combination. Furthermore, as geoprocessing tools can also be hosted on ArcGIS Servers, ESRI leaflet also enables web maps to execute geospatial analyses.
Let’s look at a few examples hosted here: http://esri.github.io/esri-leaflet/examples/.
In particular:
You see that these maps can do a lot? So how do we go about creating them?
ESRI provides really nice tutorials not only for getting started with ESRI Leaflet, but Leaflet itself:
http://esri.github.io/esri-leaflet/tutorials/. Run through the “Create your first app” tutorial:
http://esri.github.io/esri-leaflet/tutorials/create-your-first-app.html, taking note of the important concepts presented in each section (e.g. “Skeleton HTML”, “JavaScript and CSS tags”, etc.)
Copy and paste the entire contents of the last code window into a text file on your V: drive, saving the file with an .html
extension. Then open the file both in a web browser and text editor.
Once you have successfully created your map of the SF Bay Area, let’s experiment to become more familiar with what does what in this HTML page.
Change the title of the web page to Duke University
(line 5).
Change the height of the #map
object from 100%
to 500px
(line 25).
Center the map on Duke (36.005, -78.943) and change its zoom
to 18
(line 37).
Change the basemap layer to another one listed here:
http://esri.github.io/esri-leaflet/api-reference/layers/basemap-layer.html
Change the basemap layer to “Imagery” and then add basemap labels. (See http://esri.github.io/esri-leaflet/examples/basemap-with-labels.html and http://esri.github.io/esri-leaflet/api-reference/layers/basemap-layer.html)
So far, this is nothing too much beyond what Folium could do. But now, let’s explore how we can add some feature layers stored in the cloud to our map. This is explained in ESRI's next tutorial:
http://esri.github.io/esri-leaflet/tutorials/working-with-feature-layers.html .
Copy and paste the Final HTML code in Notepad++
and note the source of the features shown on the map (line 40). Go ahead and open up that link in a browser:
https://services.arcgis.com/rOo16HdIMeOBI4Mb/arcgis/rest/services/Heritage_Trees_Portland/FeatureServer/0
More detail on what's going on is provided in the tutorial page Introduction to Layer Types, but the gist of what's going on here is: to display these feature data, your HTML page instructs your web browser to send a request to an ArcGIS Server hosting these files, and handle the response – which is a JSON object – by adding those features to your map. It's the ESRI Leaflet library that facilitates converting ESRI JSON into JSON Leaflet can understand and manipulate.
Line 50 in the tutorial HTML file "binds" a popup to the features in the feature layer we added to our map and includes a function spelling out what to do if a feature is clicked on. This function opens a little callout where we clicked showing 3 attributes of the feature class. Note that the text inside the function is provided in HTML format, allowing use to manipulate font characteristics and line breaks.
How do we know what attributes are available for our feature layer? That is revealed in the URL of the feature layer itself. Open up the URL and scroll down to the Fields section. Try changing one or a few attributes in your HTML code and see what happens…
► Ok, let's again experiment:
//
) before any code. Now reload to make sure the tracts are displaying. (If not, check manually for errors or see the note on debugging at the end of this script…)Uncomment lines 50, 51, and 52
Replace the code:
<p>This tree is located at {ADDRESS} and its scientific name is {SCIENTIFIC}.</p>
with <p>{SITE_NAME}<br>{HUCODE}</p>
And maybe we should rename the variable from portlandHeritageTrees
to USGSgages
(lines 48 & 50)
You can do a lot more with these feature layers, as described in the API reference. For example, we can filter which records are retrieved from the server using a where clause. Try modifying line 48 in your web page to:
const USGSgages = L.esri.featureLayer({
url: 'http://services.nconemap.gov/arcgis/rest/services/NC1Map_Environment/FeatureServer/3',
where: "COUNTY = 'DURHAM'"
}).addTo(map);
Now, only Durham features are added to our map! To check what values are available to query, you may want to first add and view the dataset to ArcGIS Online as an ArcGIS GIS Server Connection. (Remember how to do that?)
The tutorials are not yet written for adding image layers to our maps. (Darn!) But there is an entry in the API reference that will guide to add image layers, so let's work on that: http://esri.github.io/esri-leaflet/api-reference/layers/image-map-layer.html .
Scroll to the bottom of the reference page and you'll see a snippet to add served NAIP infrared imagery to a map. This reveals the structure of how to add an image service to your map.
One of the greatest advantages of using the ESRI Leaflet API over Folium or Leaflet alone is the ability to actually provide geoprocessing capability to web sites: not just display data, but truly interact with the data. This is done through by linking a geoprocessing service to our web map. An example is shown here:
http://esri.github.io/esri-leaflet/examples/gp-plugin.html . More documentation is found here:
https://github.com/jgravois/esri-leaflet-gp
Copy the HTML/JavaScript code associated with the ESRI example and paste it into a new document on your machine. Let's walk through what's going on here that's different than in previous implementations of the ESRI Leaflet API. Additional documentation on the geoprocessing service task is here:
http://esri.github.io/esri-leaflet/api-reference/services/gp-service.html .
<div>
section is added to our web document. This will hold the status and perhaps the result of our geoprocessing operation. Notice it's id label as "info-pane" and how it's referred to elsewhere in the document. For example, it's style is defined in
lines 32-31.gpService
variable is our link to the server providing (and running) the task, and
the gpTask
is an instance of that task. More info on the service is here, and more info on
the task is here.Input_Location
is a point held in a RecordSet, the point from which you want to calculated drive time from. The second input (Drive_Times
) is a string holding the various distances to calculate, and the third, the output or Output_Drive_Time_Polygons
, includes the polygons that are returned when the tool completes.Drive_Times
parameter for the gpTask
.Lines 67-72: This is where the action is. These lines of code associate a function with a click event, meaning the function will run when the user clicks on our map.
info-pane
to read that the process is "working".evt
object (created when the user clicked) are set as the Input_Location
parameter. Now we have both the inputs for the geoprocessing task (this and the Drive_Times
).driveTimeCallback
, discussed below.response
object returned by the geoprocessing task. The function here first (line 75) resets the info-pane window, and then (line 76) draws the JSON objects returned as the response
object labeled Output_Drive_Time_Polygons
by the geoprocessing task as a Leaflet object on our map.Geoprocessing tasks are by far the most complicated tool to integrate into your web page, but certainly the most exciting. They are also the least common to find, most likely because these tasks require often intense processing time on a server. Oftentimes, and as is the case with geoprocessing tasks offered with an ArcGIS Online subscription, you need to provide authentication within your script before you can run a geoprocessing task, adding another layer of complication.
Still, it is possible and does make for great potential in creating maps that reach a far wider audience.
Copy the geoprocessing example HTML to a new document and make the following edits:
Change the title of your web document to "Message in a bottle" [Line 4]
Change the center of the map to off the coast of NC: (36.00, -75.00). [Line 51]
Change the zoom factor to 4. [Line 51]
Change the url of the service [Line56] to this:
https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_Currents_World/GPServer/MessageInABottle
Input_Location
and Drive_Times
) and one output (Output_Drive_Time_Polygons
).Update line 62 so that instead of setting a parameter called Drive_Times
to the string 1 2
, it sets the parameter named Days
to the integer 100
. [Line 62]
Input_Point
parameter of the new GP service, replacing the Input_Location
parameter referred to in the old GP service. [Line 70]gpTask
is run so that it displays the new response parameter called Output
instead of the old parameter called Output_Drive_Time_Polygons
. [Line 76]These examples, as usual, are provided to just get you started in creating web maps that consume the growing number of features, images, and geoprocessing services available in "the Cloud". Ideally, you'll be intrigued by all the stuff we didn't do in these exercises and want to go back and modify things in your HTML documents. ("What if I change the drive time values to 100, 200?")
It’s perhaps a good time now to learn how to debug your script. If you happen to mistype your JavaScript, your map may just fail to draw certain elements with no apparent error. How do we narrow in on what caused out maps to fail?
Firefox actually has a handy built-in debugger for programming JavaScript. Select Web Developer>Developer
Toolbar from the Tools menu. When you do this a bar will appear at the bottom of your browser, and if your page has any errors, the number of errors will appear at the bottom right corner. You should see a red number when the page is loaded.
Open the HTML file used in the first tutorial and change the zoom level from 10 to False. Reload your map. Nothing appears but if you have the debugging toolbar enabled, you'll see a red "1" at the bottom.
Click on the number and an error console, which is a bit like an IDE appears. There’s a lot going on here, so let’s focus on what we need. First, click on the Console tab and under that, be sure “JS” is selected. This shows any JavaScript errors or warnings that have been detected in your script.
Your error should be listed here with some luck will lead you to why your map is not showing up. You can also click on the link on the right hand side of the error and it may take you to where exactly the error occurs in your HTML file. This will be in the Debugger window. Line 32 should be highlighted and lead you to the error occurred.
You can’t edit your script in the debugger though. You have to open your HTML file in a text editor, make the changes, and then reload your page in a browser. So it’s not entirely like an IDE.
More advanced debugging requires you to inspect the values of different objects in your HTML document during its execution. The Firefox debugger has the capability to enter break points, and while you can’t “print” the values of variables as we can in the PythonWin interactive window,
In writing and debugging scripts, it’s useful to know how to comment out lines of code. The double-backslash (//) is JavaScripts comment symbol – just like the pound sign (#) is for Python. Adding these at the beginning of a line is useful for having the script ignore the line without us having to delete it. Surrounding a block of lines with /* and */ comments out the block of lines just like the triple single-quotes in Python.
Note also that, unlike Python, indentation is not important in JavaScript; we indent our html simply to make is more readable for us. What is important in JavaScript are curly braces ({ }). These serve the same function as indentation in Python, namely to frame subroutines (loops, if/then statements, etc.)