Custom Marker Controls with Mapbox and LeafletJS

I’m working on a simple mapping application to display user videos on a map. I’ve opted to use Mapbox (which is built on LeafletJS) mainly because of the styling options available.

My problem was showing and hiding markers based on their categories. Each marker has this geoJson structure:

// the marker's category object
category = { id : 1, name: 'category name' };

// the marker. all values are for demonstration
var geoObj = {
    type: 'Feature',
    geometry : { type : 'Point', coordinates : [ 53, -4 ] },
    properties : { 
        title : 'Video Title',
        video : 'http://vimeo.com/123',
        category : category
    },
};

Each category was in it’s own array, each an object with an id and name attribute as above:

maincats = [category1, category2, category3];

As far as I could google, I couldn’t find a method of adding map controls to show or hide these markers based on a property. So I rolled my own.

This will create a div of checkboxes for each category, which will show or hide all markers of that category.

Here I have the on ready event for the marker layer, which then loops through each of its markers (layers, in this case). After adding each marker to an array I build the control structure.

map.markerLayer.on('ready', function(e) 
{        
    marks = []; // array of markers
    this.eachLayer(function(marker) // loop
    {
        marker.bindPopup('pop up content etc');
        marks.push(marker); // add the marker to the array
    }

     var cats = L.control();

     cats.onAdd = function (map) {
         this._div = L.DomUtil.create('div', 'cats'); // create the control div

         // create the html for the checkboxes
         var html = '<h6>Categories</h6>';
         for(var i in maincats)
         {
             html += '<div><input type="checkbox" name="category-'+maincats[i].id+'" value="'+maincats[i].id+'" checked />'+maincats[i].name+'</div>';
         }

         // add the html to the div
         this._div.innerHTML = html;

         // add the click event listener
         L.DomEvent.addListener(this._div, 'click', function(e){

            var input = e.srcElement;
            var catid = input.value;

            if(typeof(input.value) == 'undefined') return false; // ignore random clicks on the div

            // loop through each marker, show or hide if in category
            for(var i in marks)
            {
                if(marks[i].feature.properties.category.id == catid)
                {                        
                    // check if box is checked, then show or hide accordingly
                    (input.checked) ? map.addLayer(marks[i]) : map.removeLayer(marks[i]); // each marker is a single layer
                }
            }

        });
     }
}

This works well enough, although I am yet to browser test it properly.

I suspect there may be better ways of doing this with LayerGroups, but I couldn’t get them to work at all. But this method is as good as any.

One thought on “Custom Marker Controls with Mapbox and LeafletJS”

Leave a Reply

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