Embedding a Leaflet.js Map on a Drupal Site

admin panel of content management system

As an active member of the Pennsylvania Mapping & Geographic Information Consortium (PaMAGIC), I am serving as the website admin for the organization.  A few months ago we completed the rebuild of our site using Drupal 7.x.  As our membership is primarily professionals who use maps in their daily work, we wanted to include a web map of our members.

Our initial solution was to embed our full-page map using an iframe.  This was done simply because it was the easiest solution given our limited expertise with Drupal.  And it seemed to be working fine – until I visited the membership paged through an HTTPS connection.  Because our sub-domain hosting the full-page map does not have an SSL certificate, the map was blocked.  As many of you are aware, web browsers are not allowing mixed HTTPS/HTTP content by default.  And besides, it is probably a better practice to load the map using a script instead of an iframe.

embedded PaMAGIC membership map on website

The upside of discovering this issue is that it forced my hand at learning how to embed Cascading Style Sheets (CSS) and JavaScript (JS) files on a specific page within a Drupal site.  I have done this with WordPress, so I didn’t think it would be too difficult.  And it wasn’t, except when I realized my CSS and JS was loading on every single page.  Fortunately, I was able to fix a conditional statement resolve the issue.  I wanted to share the steps I took to implement this solution.

 1. Storing Assets on the Server

The first step was storing all of the related CSS and JS files on our web server.  I placed all related files in the /sites/all/themes/[active theme] directory of the Drupal install.  I created a folder at this level that included the Leaflet.js core and plugin files.  I also created a maps directory to house the code for each embedded map we create.

2. Creating Container Element on Specified Page

The next step was creating the container element for the map on the page I wanted to embed the map on.  Within the editor interface, I switched to “Switch to plain text editor” and added the following markup:

<div id="membershipMap">
<div id="memberSearch"></div>
</div>

The #membershipMap div will be referenced when we construct the map object, as is standard practice with Leaflet.js.  the #memberSearch div contains a form where users can search for members by name or search by street address.

3. Develop the Map

The next step is to write the code for the map application.  This was pretty simple, as I was just refactoring the code from the full-page map for the embedded map.  One major change is that I wrapped all of the code within a self-invoking function.  This was to keep the global namespace clean, which seems to be good practice when integrating custom JavaScript with CMSes.  You can see below that I use jQuery in my map.  I also created a CSS file just for my map. I thought this was more maintainable than adding the map-specific code to the site-wide stylesheet.

(function initMap() {
   # code for map app
})(jQuery)

 4. Load JavaScript and CSS on a Specific Page

Finally, we get to the challenging part.  And I’ll be the first to admit there are different ways to complete this task.  My solution utilized the template.php file located in the sites/all/themes/[theme] directory of the Drupal install.  I hooked into the theme_preprocess_node function.  While I’m not sure what this function actually does, I hooked into it because I found this article when searching how to load JS and CSS files on specific pages.

Within this function, I run a conditional test using drupal_get_path_alias so that the JS and CSS files are only loaded if the page alias matches the page I want the map on.  Again, there is probably a better way to do this using the node ID, as that is more permanent than the page alias.  Within the conditional statement, I call the drupal_add_css and drupal_add_js methods to load the neccassary JS and CSS files.

You’ll notice I set the option for requires_jquery to true for the map.js file.  This ensures that jQuery is loaded before the map.js script.  You’ll also notice the stylesheet for the map is named style.min.css.  It is not a minified file.  Whenever it was named style.css, it would not  load on the page.  This was my workaround so it would be loaded.

Here is what the result looked like for me:

function responsive_preprocess_node(&$variables) {
  // other code from the theme

  /*** add leaflet css and js ***/
  if (drupal_get_path_alias() == 'members') {
        // Font Awesome
        drupal_add_css(drupal_get_path('theme', 'responsive') . '/font-awesome/font-awesome-4.7.0/css/font-awesome.min.css');
        // Leaflet Core
        drupal_add_css(drupal_get_path('theme', 'responsive') . '/leaflet/foundation/leaflet.css');
        drupal_add_js(drupal_get_path('theme', 'responsive') . '/leaflet/foundation/leaflet.js',  array('type' => 'file', 'scope' => 'footer'));
        // Leaflet ZoomHome
        drupal_add_css(drupal_get_path('theme', 'responsive') . '/leaflet/plugins/leaflet.zoomhome-0.2.0/leaflet.zoomhome.css');
        drupal_add_js(drupal_get_path('theme', 'responsive') . '/leaflet/plugins/leaflet.zoomhome-0.2.0/leaflet.zoomhome.min.js',  array('type' => 'file', 'scope' => 'footer'));
        // Leaflet Locate
        drupal_add_css(drupal_get_path('theme', 'responsive') . '/leaflet/plugins/leaflet-locatecontrol-0.52.0/L.Control.Locate.min.css');
        drupal_add_js(drupal_get_path('theme', 'responsive') . '/leaflet/plugins/leaflet-locatecontrol-0.52.0/L.Control.Locate.min.js',  array('type' => 'file', 'scope' => 'footer'));
        // Esri Leaflet
        drupal_add_js(drupal_get_path('theme', 'responsive') . '/leaflet/esri/esri-leaflet-v2.0.7/esri-leaflet.js',  array('type' => 'file', 'scope' => 'footer'));
        // Esri Leaflet Renderers
        drupal_add_js(drupal_get_path('theme', 'responsive') . '/leaflet/esri/esri-leaflet-renderers-v2.0.4/esri-leaflet-renderers.js',  array('type' => 'file', 'scope' => 'footer'));
        // Esri Leaflet Geocode
        drupal_add_css(drupal_get_path('theme', 'responsive') . '/leaflet/esri/esri-leaflet-geocoder-v2.2.4/esri-leaflet-geocoder.css');
        drupal_add_js(drupal_get_path('theme', 'responsive') . '/leaflet/esri/esri-leaflet-geocoder-v2.2.4/esri-leaflet-geocoder.js',  array('type' => 'file', 'scope' => 'footer'));
        // Membership Map
        drupal_add_css(drupal_get_path('theme', 'responsive') . '/leaflet/maps/members/style.min.css');
        drupal_add_js(drupal_get_path('theme', 'responsive') . '/leaflet/maps/members/map.js', array('type' => 'file', 'scope' => 'footer', 'requires_jquery' => TRUE));
    }
}

 

I’m completely aware there is probably a better way to embed a Leaflet.js map on a page within a Drupal site.  However, this method worked for me, and I wanted to share it with others, as this process was more complicated than I anticipated.  If you’ve embedded maps on Drupal sites using different methods, I would love to hear about those.  Feel free to comment.

Advertisements

One thought on “Embedding a Leaflet.js Map on a Drupal Site

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s