knownasilya / ember-leaflet-cartodb

Ember-Leaflet CartoDB.js Layer
http://knownasilya.github.io/ember-leaflet-cartodb/
MIT License
2 stars 1 forks source link

CartoDB layer events don't propagate #3

Open allthesignals opened 7 years ago

allthesignals commented 7 years ago

CartoJS has a number of helpful events for getting information about map state: https://carto.com/docs/carto-engine/carto-js/events/

I'm still thinking through how to approach this, but it starts with following ember-leaflet's structure and adding those events here: https://github.com/knownasilya/ember-leaflet-cartodb/blob/master/addon/components/cartodb-layer.js#L15

For starters, the "load" event would be extremely useful, but so far using it on the component ({{cartodb-layer onLoad='controllerAction'}}) throws an error: addEventListener is not a function. This is thrown because ember-leaflet first generates semantic names for events, then calls this method with the assumption that the layer is part of Leaflet's core: this._layer.addEventListener(eventName, this._eventHandlers[eventName], this);

Maybe the layer needs to be wrapped in a custom Leaflet layer class? I've tried explicitly defining the missing method, but I'm not sure that's the right approach.

var MyCustomLayer = L.Class.extend({

    initialize: function (latlng) {
        // save position of the layer or any options from the constructor
        this._latlng = latlng;
    },

    onAdd: function (map) {
        this._map = map;

        // create a DOM element and put it into one of the map panes
        this._el = L.DomUtil.create('div', 'my-custom-layer leaflet-zoom-hide');
        map.getPanes().overlayPane.appendChild(this._el);

        // add a viewreset event listener for updating layer's position, do the latter
        map.on('viewreset', this._reset, this);
        this._reset();
    },

    onRemove: function (map) {
        // remove layer's DOM elements and listeners
        map.getPanes().overlayPane.removeChild(this._el);
        map.off('viewreset', this._reset, this);
    },

    _reset: function () {
        // update layer's position
        var pos = this._map.latLngToLayerPoint(this._latlng);
        L.DomUtil.setPosition(this._el, pos);
    }
});

map.addLayer(new MyCustomLayer(latlng));

I'm working on adding a failing test for this and will continue looking into it, but any help is appreciated!

allthesignals commented 7 years ago

From @miguelcobain on Slack:

i suggest you mimic what ember-leaflet does for leaflet events creating an array like cartoDbEvents And then using something like ember-leaflet’s _addEventListeners (https://github.com/miguelcobain/ember-leaflet/blob/master/addon/components/base-layer.js#L93-L113) but with the CartoDb specificities You’ll need a _removeEventListeners as well. if you override it, I think you should call this._super(…arguments); because if you don’t then leafletEvents array is useless. I see that the addon isn’t using it at the moment. But I think we shouldn't break that, if we can. great, will do. thanks so much. But just so I understand, I should create another events array here: https://github.com/knownasilya/ember-leaflet-cartodb/blob/master/addon/components/cartodb-layer.js#L14 yes. declare it as a concatenated property as well: https://github.com/miguelcobain/ember-leaflet/blob/master/addon/components/base-layer.js#L12 That way, if users extend your component (say, for a carto db plugin or something), they can specify only the additional events while overriding that array. (edited)

knownasilya commented 7 years ago

FYI I added an onClick action, but it only works with Leaflet <= 0.7.7. Interactivity doesn't work with 1.0 😦