Leaflet Web Map Helper Functions

two people holding hands near the ocean

I believe it was back at GIS Day 2015 when I decided I was going to give the Leaflet.js web mapping library a shot.  I had some HTML and CSS skills under my belt, and knew a little bit about JavaScript.  I started by creating simple embedded maps.  My first full-page app had a weak design, but got the job done.  I soon learned about the BootLeaf and Esri Calcite Maps projects, which provide a great Bootstrap user interface to the mapping application.

Through this journey of developing web mapping applications, I discovered various helper functions that I believe create a better experience for the user.  I wanted to share a few of these.  I’ll add links to some maps I’ve created at the end.

Helper Functions

Setting the Initial Map Zoom Level

When you construct the map object in Leaflet, there is an option to set the zoom level (or map scale).  I quickly found that having the same zoom level on desktop computers and mobile phones provides a less than ideal user experience.  So I created a function that returns the zoom level based upon a series of conditional statements that test the browser width.  Here is the sample:


// Set the initial map zoom level based upon viewport width
function setInitialMapZoom(windowWidth) {
    // create variable for map zoom level
    var mapZoom;    

    // test for various browser widths
    if (windowWidth < 500) {
mapZoom = 9;
} else if (windowWidth >= 500 && windowWidth < 1000) {
       mapZoom = 10;
    } else {
       mapZoom = 11;
    }

    // provide a responsive initial map zoom level based on browser width
    return mapZoom;
}

// Pass the function into the map constructor
var map = L.map('map', {
   center: [40.125, -80.258],
   zoom: setInitialMapZoom(windowWidth)
});


Setting Max Height and Width for Popup

I also found that it is beneficial to provide height and width constraints for layer popups on mobile devices.  Similar to the previous function, there is a set of conditional tests that assign the max height and/or width for the popup, based upon the browser height/width.  In practice, the result has been a vertical scroll bar on mobile devices and popup windows that have margin to the left or right.  I have a separate function for popup height and width.  I also use the browser window area (height X width) for the max height function. The function is called within the options of the the bindPopup() method.

// Set max width of pop-up window
function setPopupMaxWidth(windowWidth) {
   // create variable for max width
   var maxWidth;

   // test for various browser widths
   if (windowWidth < 450 ) {
      maxWidth = 240;
   } else {
     maxWidth = 300;
   }

   // control popup width based upon device width
   return maxWidth;
}

// Bind popup to a layer
layer.bindPopup(function(evt,layer) {
   // add content
   return L.Util.template("
<div>
<h1>{Name}</h1>
</div>
", evt.feature.properties);
}, {closeOnClick: true, maxHeight: setPopupMaxHeight(windowArea), maxWidth: setPopupMaxWidth(windowWidth)});

Controlling Map Tooltips

One of the great features of the 1.x release of Leaflet was the ability to add tooltips to features.  Let’s say you have a map of farmer’s markets.  Whenever you mouse-over a site, you would get a tooltip with the name and address of the market.  But what about for touch devices, which don’t emit a mouse-over event?  By default, when you would press on a site, you would get a tooltip and a popup to open, which if you ask me, doesn’t make sense.  My solution was to use Leaflet’s L.Browser.touch, which detects touch devices.  If the browser isn’t on a touch device, then I call a function which binds a tooltip to a layer.  An additional step I take for non-touch browsers is that I unbind the tooltip when the popup is open, and then bind it when the popup closes. Below is sample code:


// boolean if browser is on a touch device or not
var isTouchDevice = L.Browser.touch;

// Add tooltip to farmers markers
function bindTooltipFarmMarkets() {
   // use Leaflet's bindTooltip method
   farmMarkets.bindTooltip(function(evt) {
      // create HTML content for tooltip. Assumes using GeoJSON
      return L.Util.template("<span>{Name}, located at {Address}, {City}, {State}, {Zip}</span>", evt.feature.properties);
      }, {opacity: 1, interactive: true});
}

// Add Popup to farmers markets
farmMarkets.bindPopup(function(evt, layer) {
    // for non-touch devices, close tool tip when popup opens
    if (!isTouchDevice) {
        evt.on("popupopen", function() {
           // remove tooltip on popup open event
           farmMarkets.unbindTooltip();
        });
        // add tooltip on popup close event
        evt.on("popupclose", bindTooltipFarmMarkets);
    }

// other code for bindPopup method
});    

// Add tool tip for non-touch browsers
if (!isTouchDevice) {
    bindTooltipFarmMarkets();
}

So that’s a sample of a few functions/tricks I use whenever I’m creating a Leaflet web map app.  Hopefully you’ve found these useful.  If you want to check these out in action, I’ve included links to a couple apps I’ve developed.  I would suggest using Chrome’s developer tools to see how the apps respond across browser sizes.  Or you could visit it on your computer and phone/tablet as well.

Sample Maps

Cumberland County Recycling & Disposal Map (uses BootLeaf)

Cumberland County Magisterial District Judges (uses Calcite Maps)

Advertisements

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