-
-
Save pospi/85c31530c4a93cf091ce to your computer and use it in GitHub Desktop.
| /** | |
| * Service to manage geoJSON layering with Leaflet.js' angular directive, which only allows 1 set of geoJSON data. | |
| * | |
| * Assuming you have a leaflet directive with its 'geojson' attribute set to `geojson`, usage is as follows: | |
| * var layers = new GeoJSONLayers(); | |
| * | |
| * layers.addLayer('myLayer', geoJSON, function(feature) { return { fillColor: '#00F' }; }); | |
| * $scope.geojson = layers.get(); | |
| * | |
| * layers.removeLayer('myLayer'); | |
| * $scope.geojson = layers.get(); | |
| */ | |
| angular.module('MyApp').factory('GeoJSONLayers', [ | |
| function() { | |
| var handler = function() | |
| { | |
| this.clear(); | |
| }; | |
| handler.prototype.clear = function() | |
| { | |
| this.json = { | |
| type : "FeatureCollection", | |
| features : [] | |
| }; | |
| this.layerStyles = {}; | |
| }; | |
| handler.prototype.addLayer = function(layerID, geoJSON, styleCallback) | |
| { | |
| this.layerStyles[layerID] = styleCallback; | |
| // tag features with their assigned layer | |
| geoJSON.features.forEach(function(feature, i) { | |
| feature.properties.__LAYERID__ = layerID; | |
| }); | |
| // merge into current objects | |
| Array.prototype.push.apply(this.json.features, geoJSON.features); | |
| }; | |
| handler.prototype.removeLayer = function(layerID) | |
| { | |
| var feats = this.json.features, | |
| i = 0; | |
| delete this.layerStyles[layerID]; | |
| // remove relevant geoJSON objects as well | |
| for (; i < feats.length; ++i) { | |
| feature = feats[i]; | |
| if (feature.properties.__LAYERID__ == layerID) { | |
| feats.splice(i, 1); | |
| --i; | |
| } | |
| } | |
| }; | |
| handler.prototype.__handleStyle = function(feature) | |
| { | |
| if (feature.properties['__LAYERID__'] === undefined) { | |
| return {}; | |
| } | |
| return this.layerStyles[feature.properties.__LAYERID__](feature); | |
| }; | |
| // return geoJSON data for assignment to scope | |
| handler.prototype.get = function() | |
| { | |
| var self = this; | |
| return { | |
| data: this.json, | |
| style: function(feature) { | |
| return self.__handleStyle.call(self, feature); | |
| }, | |
| resetStyleOnMouseout: true | |
| }; | |
| }; | |
| return handler; | |
| } | |
| ]); |
I've had a brief flick through that old codebase and found a comment near my assignment of onEachFeature that says "we can't use delegated events on the whole layer, because MultiPolygons are disassociated from their features that way".. I think that might be the reason yours is having issues, perhaps Leaflet does weird stuff to the function context internally?
In any case I found my layer loading function inside the map component, it's just a standard call to L.geoJSON() with an onEachFeature option. The key is probably that my onEachFeature is a generator function that returns a new function for every layer it's initialised on:
function configureFeature(layerId)
{
return (function() {
var theLayer = layerId;
return function(feature, layer) {
layer.on('mouseover', someHandler);
};
})();
}
You can then create different logic for your layers by switching on theLayer. Hope that helps a little bit!
@pospi Thanks for the response - that's actually exactly the problem I ran into.
I'm using the angular leaflet wrapper, so I just did:
angular.extend($scope, {
geojson: {
data: (myGeoJsonLayer.get()).data,
pointToLayer: (myGeoJsonLayer.get()).pointToLayer,
onEachFeature: function (feature, layer) {
layer.bindPopup('Hey, listen!');
}
},
Thanks for the solution, I can't believe it was so simple.
By the way - if anyone is interested here is my fork that supports the pointToLayer option. Thanks 👍
https://gist.github.com/absolutelynotjames/c7688054e1325128438e2cef1686eea0
Edit: @pospi I've made a bit of progress, I got pointToLayer working:
handler.prototype.addLayer = function(layerID, geoJSON, styleCallback, pointToLayerCallback, onEachFeatureCallback)this.pointToLayer = pointToLayerCallback;I can't get this to work for onEachFeature though. Any advice? Thank you!