Wednesday, February 26, 2014

Ember, Leaflet and Leaflet.Draw

I spent some time trying to figure out how to hook all these components together and decided to document the process here in case someone else is struggling with this as well.

I had a minimalistic Ember project in which I wanted to use Leaflet maps. I quickly found out about the ember-leaflet project. I added the ember-leaflet.js dependency to my index.html and following code into my ember application:

App.TileLayer = EmberLeaflet.TileLayer.extend({
    tileUrl: 'http://localhost:7000/tiles/{z}/{x}/{y}.png'
});
App.MapView = EmberLeaflet.MapView.extend({
    childLayers: [App.TileLayer],
    center: [34.227, -118.55],
    zoom: 11
});
Only problem I had with this, was that the leaflet map was taking too much space. Basically it filled the whole ember view. So, when I had other stuff in my handlebars template (besides the  <div id="map"></div> placeholder), the map would fill the whole template pouring over the other elements that I had in my template. This is why I ended up creating another ember view inside the outer view that would only contain the map. Then in the parent template I would have all my html elements as before but where I previously had the div-placeholder for the map, I put {{render "map"}} and then in map.hbs file just the map-div:  <div id="map"></div>.

So far so good.

I also needed draw controls and sure enough, Leaflet.Draw had everything I wanted. I added the css and js files into my project and added following options to my map configuration:

App.MapView = EmberLeaflet.MapView.extend({
   childLayers: [App.TileLayer],
   center: [34.227, -118.55],
   zoom: 11,
   options: {
       drawControl: true
   }
});
That would show the controls on the map just fine, but I wanted to get the edit controls working as well and as Leaflet.Draw documentation tells us I needed to create the Draw controls myself. I wasn't quite sure where to put that code so I ended up overriding the didCreateLayer and initialising the drawing controls there. But I still wasn't able to hook to all the events that Leaflet.Draw provides. Of course, I probably could have gotten the leaflet map handle from ember-leaflet and attach my event handler directly there, but that seemed like a hack. Going through the ember-leaflet code I noticed that it internally uses concatenatedProperties: ['events'] to gather all supported events. After that I just introduced that property in my derived view and added all Leaflet.Draw events there. At that point the code looked like this:

App.MapView = EmberLeaflet.MapView.extend({
    childLayers: [App.TileLayer],
    center: [34.227, -118.55],
    
    zoom: 11,

    events: [
        'draw:created',
        'draw:edited',
        'draw:deleted',
        'draw:drawstart',
        'draw:drawstop',
        'draw:editstart',
        'draw:editstop',
        'draw:deletestart',
        'draw:deletestop'
    ],

    didCreateLayer: function () {
        this._super();

        var map = this.get('layer'),
            drawnItems = new L.FeatureGroup(),
            drawControl;


        this.set('drawnItems', drawnItems);
        map.addLayer(this.drawnItems);
        drawControl = new L.Control.Draw({
            edit: {
                featureGroup: this.drawnItems
            }
        });
        map.addControl(drawControl);
    },

    "draw:created": function (e) {
        var layer = e.layer,
            type = e.layerType,
            drawnItems = this.get('drawnItems'),
            bounds;

        drawnItems.addLayer(layer);
        return this;
    }
});

That was it. Now I'm able to get all the Leaflet.Draw events to my view.



Monday, February 17, 2014

Doctor of Lego

So, I finally got my Ph.D.

With Professor Cesare Pautasso from University of Lugano being the opponent in my defence, we had good discussions. The topic of my dissertation is "Engineering Web Applications: Architectural Principles for Web Software". In case you are interested in getting the pdf file, here's the link.



The whole process took couple of more years than I was hoping for because I was really caught up with the implementation side of these things in the company I work for. It would've been nice to publish this few years earlier but no harm done. If you're looking for a TL;DR version of my dissertation this post is a very brief summary of the subject.