Adding labels to ember-leaflet markers

Ember-leaflet is a great add-on that makes it really easy to add Leaflet.js maps to your Ember application via components:

{{#leaflet-map center=center zoom=zoom}}
  {{tile-layer url="http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png"}}
  {{#each model as |place|}}
    {{marker-layer location=place.location}}
  {{/each}}
{{/leaflet-map}}

I recently wanted to add labels to each marker on my map that display when the user hovers on the marker:

Image of a label on a leaflet map

Thankfully, there is already a Leaflet.js library called Leaflet.label to help do this, so we just need to incorporate it into our Ember app.

To do this, we need to create our own custom component that is based on an ember-leaflet marker component. This will deal with adding the labels when each marker is created.

So first make sure you have installed the Leaflet.label library:

bower install --save Leaflet.label

and then create a custom marker component:

ember g component label-marker-layer

Now add the following to your new component.js:

/* global L */

import BaseLayer from 'ember-leaflet/components/base-layer';
import toLatLng from 'ember-leaflet/macros/to-lat-lng';

export default BaseLayer.extend({

  leafletRequiredOptions: [
    'location'
  ],

  leafletOptions: [
    'label', 'icon', 'clickable', 'draggable', 'keyboard', 'title',
    'alt', 'zIndexOffset', 'opacity', 'riseOnHover', 'riseOffset'
  ],

  leafletEvents: [
    'click', 'dblclick', 'mousedown', 'mouseover', 'mouseout',
    'contextmenu', 'dragstart', 'drag', 'dragend', 'move', 'remove', 'add',
    'popupopen', 'popupclose'
  ],

  leafletProperties: [
    'icon', 'zIndexOffset', 'opacity', 'location:setLatLng'
  ],

  location: toLatLng(),

  createLayer() {
    var marker = this.L.marker(...this.get('requiredOptions'),
                               this.get('options'));

    var label = this.get('options.label');
    if(label) {
      marker.bindLabel(label, {
        offset: [-50, -95]
      });
    }
    return marker;
  }
});

All we have done is added a new label option to pass into our component which will contain the content we want to display. We then simply create the label in the createLayer() method. Now to use it in a template:

{{#leaflet-map center=center zoom=zoom}}
  {{tile-layer url="http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png"}}
  {{#each model as |place|}}
    {{label-marker-layer label=place.label location=place.location}}
  {{/each}}
{{/leaflet-map}}

This approach gives you a lot of control over the Leaflet.label, so you can play around with settings, add second labels and more.