Using OpenLayers 3 with Ember.js

OpenLayersLast week we announced the release of OpenLayers 3 Beta 2, so this week I wanted to share some recent experiments combining OpenLayers 3 and Ember.js to create a LayerSwitcher that supports grouping and overlays as well as base layers.

This was my first attempt to use Ember.js, an open-source client-side JavaScript web application framework based on the model-view-controller (MVC) software architecture pattern. It uses the Handlebars library for its templates.

Some of my takeaways from this exercise were:

  • Ember seems powerful, and easy to learn. However, it’s sometimes hard to scrape together all the resources needed to learn and extend the framework.
  • Components are pretty new to Ember and I couldn’t figure out how to properly define a component in a different namespace and use it in the application template (this is why I needed to use a workaround).
  • OpenLayers 3 also has observable properties, which makes it easier to integrate the two.

Using Ember

I initially created the application using the Ember starter kit. In the HTML page, I created a template for the layer switcher component. Components in Ember have an id that starts with components followed by a hyphenated component name:

<script type="text/x-handlebars" id="components/layer-switcher">
    <ul><h4>{{group}}</h4>
    {{#each item in model}}
      <li>
        {{#if item.exclusive}}
        <label>{{view Ember.RadioButton name=group
            selectionBinding="selected" valueBinding="item.title"
            checkedBinding="item.visible"}} {{item.title}}</label>
        {{else}}
        {{view Ember.Checkbox checkedBinding="item.visible"}} {{item.title}}
        <button class="btn btn-default btn-xs" 
          {{action "removeSelected" item}}>
          <span class="glyphicon glyphicon-trash"></span>
        </button>
        {{/if}}
      </li>
    {{/each}}
    </ul>
</script>

Close-up of layer switcher component
As shown in the image at right, this template shows a radio button if the layer’s group is exclusive, otherwise it shows a checkbox and a remove button. If the selected radio button is changed, the value of the selected property is changed to the title of the selected item. If an item is visible in the exclusive group, it will initially be checked. In the index template, this component is then used per group.

Grouping layers

I used the Ember.GroupableMixin extension to group the layers array based on an object property. All of the OpenLayers.Layer objects were created with a group property that groups them together in the layer switcher. The groupable mixin is then used in an Ember.ArrayController where also the name of the property to use for grouping is specified.

The model for the application uses a utility function defined in a separate namespace (Boundless). This function simply turns the OpenLayers.Layer objects into corresponding Ember objects. The definition of those Ember objects can be found in the Boundless.MapLayer object.

Two-way binding

This is a two-way binding, so if the visibility of the layer is changed by OpenLayers then the Ember object will be updated automatically:

layer.on('change:visible', function(evt) {
    this.set('visible', evt.target.get('visible'));
}, this);

Where this is the Ember MapLayer object.

If the visible property is changed by Ember, the OpenLayers state will be changed as well:

this.addObserver('visible', layer, function(evt) {
    this.set('visible', evt.get('visible'));
});

Where this is the OpenLayers.Layer object. As you can see, having the mechanism of observable properties on both sides of the equation is extremely powerful.

Exclusive layers and the remove button

The LayerSwitcher component code handles the selection of the radio group for exclusive layers. Please note that exclusive is not a property of a layer defined by OpenLayers, but defined by this application. However, the OpenLayers.Layer object can take additional observable properties, which is convenient here. The same applies to group. Also, if somebody removes an item from the layers collection in OpenLayers, our Ember view needs to be updated, this is handled by the component code as well.

this.map.getLayers().on('remove', function(evt) {
  var el = evt.getElement();
  this.model.removeObject(this.model.findBy('title', el.get('title')));
}, this);

Lastly, to remove an overlay layer from the map, the component defines an action that is tied to a button. In this case the object needs to be removed from the OpenLayers.Map as well.

Results!

A live version of this application can be found here.

Screen shot of the layer switcher application

Interested in using OpenLayers in your enterprise? Boundless provides support, training, and maintenance. Contact us to learn more.

EmailTwitterFacebookGoogle+tumblrLinkedIn

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>