A Leaflet map with Node.js, MongoDB and Heroku

Back from an amazing FOSS4G 2016 conference in Bonn – if you have not yet been to a FOSS4G conference, I would highly recommend you attend the event at some stage, if not the international conference which is in Boston (2017), then look out for the national conferences. Consider presenting or holding a workshop, both these options are a great way to get involved and give something back to a truly supportive community.

In Bonn I delivered a 4 hour workshop entitled A Leaflet map with Node.js, MongoDB and Heroku this is a variation of my post A Leaflet map with Node.js and MongoDB but you will notice the addition of Heroku – a platform as a service (PaaS) that enables developers to build and run applications entirely in the cloud. I used the Heroku platform together with mLab, a MongoDB hosting platform cloud Database-as-a-service in an effort to simplify the hosting process rather than try to configure this for each person attending the workshop. Both of these services are really easy to use and have free starter options to get you going.

The following is a tutorial working through the workshop I delivered at the Bonn FOSS4G 2016 event. We had a full class, thanks to those who attended I hope you enjoyed it. I would also like to thank Marek Balint for his assistance setting up the workshop and for my sponsor 1Spatial for the generous support and funding.

 

1spatial

Thanks also to Heroku and MongoDB for the stwag and a big thanks to the event organisers especially Carmen for all their hard work and time they invested making the event the success it was.

 

To begin, create an Heroku and mLab account, then you will need the following installed before you move on:

 

Heroku base application

The Getting Started on Heroku with Node.js tutorial provided by Heroku is a great reference and we will be using this to get the base Node.js up and running, the plan is to extend this to work with Mongo and Leaflet.

Log in using the email address and password you used when creating your Heroku account, according to the tutorial, authenticating is required to allow both the heroku and git commands to operate.

Get the node-js-getting-started app from github then navigate to the node-js-getting-started directory.

To deploy the app, you will need to create a space on Heroku, this will be associated with your local git repository and assigned a random name, this name can be changed but we are not going to make any changes in this tutorial. There is a limit of 5 apps for unverified (free) accounts so if you run the following command it will only work if you have not used your 5 application allocation.

Now the space has been created and named we can deploy the local app

Visit the app at the URL generated by its app name by running the following command

You will see the following page – hit  Ctrl + c to exit.

gettingstarted

 

The app can also be run locally, to do this you will need to install the app dependencies locally, you can do this by running the following

npm install takes a look at the package.json file and gets all the dependencies listed in this file, we will add to this later, at which time we will need to re-run the npm install command. Once you have run npm install, run the following to deploy your app locally

If the app wasn’t closed down (Ctrl + c) in a previous session, you might get a ‘port is busy’ conflict you may need to free up the port using something similar to the following

In your browser go to http://localhost:5000/ to view the same result as you got from running the heroku open command, but this time its running locally. Hit  Ctrl + c to exit.

If you would like to assign a local app in this case node-js-getting-started with a pre-existing personal app on Heroku rather than creating a new one then you need to specify the remote location, in the case below, setting the remote location to a pre existing app named vast-temple-63834

You now have a base application, we will take a brief detour to explore Leaflet and MongoDB and return shortly to extend our application – next stop leaflet.

 

Leaflet

Developed by Vladimir Agafonkin with a first release in 2011, Leaflet is a widely used open source JavaScript library. Leaflet is slightly lighter on functionality than OpenLayers but is built for speed and compatibility with web mapping applications, it also works well with GeoJSON which is what we will store in MongoDB and use to display our spatial features in the map view.

Lets take a look at the anatomy of a simple Leaflet map. The Leaflet material for this tutorial can be found on GitHub. The basic.html example can be found at the leaflet quickstart guide page – this page provides a great explanation of what each line of code is doing and how it works together to produce the simple quick start example. The only change I have made to the quick start example is to set the map view to occupy the full page – this can be achieved using the following css:

I have also extended the quick start example to include some static json data which we will use later in MongoDB to use in our Node.js application. In addition to the json, I have added some bootstrap styling, this gives us a nice bar along the top of our map where we can place a company logo and reference to a home page etc. I have also introduced a simple layer legend that we will wire up to our json data so that we can toggle layers on and off.

From the tutorial resources on GitHub, open the node_template.html file in your favourite editor and lets take a look at the differences between this file and the basic.html (quick start example)

On lines 4 and 5: link that explains the Chrome – Origin null is not allowed by Access-Control-Allow-Origin security error and relates to loading files from the same directory as the document, in this case, the json data. For our final application, we will use a remote instance of MongoDB so we will not have this issue.

Lines 19 – 28: reference bootstrap, jquery and style.css. The bootstrap references relate to the styling of the black menu bar along the top of the page. Jquery provides additional functionality such as the getJSON function that handles the json data. The style.css file provides style for map content.

Lines 34 – 45: HTML responsible for the menu bar and its content

Lines 51 – 58: HTML responsible for the map legend

Lines 66 – 69: fetch the json data from the file location data/points.json and sends it to the addLayer function

Lines 72 – 103: the addLayer function handles the json data and transforms this into a Leaflet layer based on its type value. In this case the function is able to handle the type values of MultiPoint, MultiLineString and Polygon. Since we know the data we know anything other than MultiPoint and MultiLineString will be Polygon, we cannot assume this with data we do not know so it might be a good idea to build a more robust function to handle unknown data.

The geoJson() function allows you to parse GeoJSON data and display it on the map. In the case of the MultiPoint and MultiLineString data, the styling is derived from the json content style value. For the Polygon data the json style value is used in the JavaScript switch statement where a style is constructed based on the style value of Orange or Blue.

The bindPopup() function handles the feature onclick action and returns a popup with layer.type value for MultiPoint and MultiLineString feature.properties.name for Polygon features

Lines 105 – 111: handles the toggle on off for the three map layers

A quick look at the lines.json file reveals the coordinate pairs that make up the lines as well as the type, name and style values, any of these can be used in the JavaScript function to customise style and popup content.

Note that with Leaflet map content, the layer is destroyed and re-created when it is toggled on and off, this means that the last layer toggled on will be placed on top of the layer stack. This can be handy since time is not wasted trying to calculate layer order, but, it can also pose a problem if you need a certain layer/s to remain in a pre-defined position. In the node_template example, toggle the polygons layer on and off and notice how they re-appear over the point and line layers. Popups can not be returned for a feature that is hidden under another feature – of course this can be handled in the script but does not occur by default. This might not pose a problem at all, but is worth a mention. If this is a problem check out OpenLayers3 as a more feature rich but heavier alternative to Leaflet.

On to MongoDB. Assuming you have downloaded MongoDB Community Edition, login to your mLab account. From the home page, click the Create new button to create a new MongoDB deployment. Select a region then switch to the single node tab and select the free Sandbox option, finally, give the database a name then click on the create new MongoDB deployment button.

Click on the Users tab then click Add database user

Click on name of the newly created database add collection. Add a user name and password, you will need these to connect to the database and add content. Look for the connection string at the top of the page, it should read something like:

Add and run the line above in your terminal remembering to insert user and password information, you should see something similar to the following:

At this point, you can add content, at the prompt simply paste in the following, change the name layer_collection to match the name of your collection

If the insert was successful, a refresh of the mlab page should reflect 3 new documents, these are the point line and polygon items you have just added. These are now ready to use in our node application.

 

Extending Node.js

Returning to the node-js-getting-started base app, delete the directory named node_modules, we will rebuild this based on the modules we need for our leaflet application. Open the package.json file and edit to look like the following:

Notice the references to the pug and mongodb modules, we will use these to generate HTML and connect with our MongoDB content. Once you have edited the package.json file, run the following command in the terminal:

You will notice that a new node_modules directory is created, it now contains only the modules we need for our leaflet application.

Next, edit the index.js file to include the following content, this will ensure our connections are wired up correctly to MongoDB and setup our URL requests for data. Dont forget to adjust connection strings to match your connection details.

I did not go into detail about the content of this file in the workshop, but, if you are interested, I have given it a lot of explanation in my other tutorials.

In the public > stylesheets directory, create a file called style.css with the following content:

Then finally, in the views > pages directory, add the following three files:

index.pug

layout.pug

map.pug

Test the application locally by running the following command:

Deploy the app by running the following command:

Run the deployed app by running the following command:

I hope you have enjoyed this post, you can find the source files for this workshop on GitHub, I have also included the FOSS4G workshop json data. Please let me know if you have any comments or questions.

 

 

 

 

 

 

  5 comments for “A Leaflet map with Node.js, MongoDB and Heroku

  1. san
    February 6, 2017 at 11:11 am

    I guess you meant this link https://github.com/denelius/nodejs_leaflet_mongodb_heroku/tree/master/WS26 to reach the workshop’s sources, instead of the one you gave above as https://github.com/denelius/nodejs_leaflet_mongodb_heroku/tree/master/leaflet.

    Thanks for the great tutorial.
    Cheers

    • denelius
      February 27, 2017 at 10:51 pm

      Thanks San I have made that edit

  2. San
    June 20, 2017 at 11:02 am

    After a while I have got back to try this tutorial again. Yet I am having this one issue.
    Event though I can view the map locally with no issues, I cannot see the same result when I pushed the files to Heroku. Similar to the localhost, an express welcome page appears showing the link to the map, yet when I have clicked on the link there is nothing but the legend on the top-right corner of the screen.
    What do you think might be the reason for that? Can you please help me out?

    below is the link to the heroku app, just so you can see the issue I have explained above.

    https://lit-headland-53713.herokuapp.com/

    Thanks a lot

    • denelius
      June 20, 2017 at 12:04 pm

      Hi San, I have just checked out your site in Chrome, as you mentioned, the Express page works fine. I clicked on the map link an noticed a little red icon top right of the browser (red x on grey shield) if you mouse over this icon it reads “this page is trying to load scripts from unauthenticated sources”. If you click on the icon your page will appear and looks to be working correctly. This might be the same issue as some of the others have been experiencing.

Leave a Reply

Your email address will not be published. Required fields are marked *