-
-
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; | |
} | |
]); |
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;
handler.prototype.__handlePointToLayer = function(feature, pointToLayer)
{
return this.pointToLayer(feature).options;
}
pointToLayer: function(feature, latlng) {
return L.marker(latlng, self.__handlePointToLayer.call(self, feature, latlng));
},
I can't get this to work for onEachFeature though. Any advice? Thank you!
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
@pospi this is really helpful - thanks for sharing. How would I go about adding in support for pointToLayer, and onEachFeature options? I shamefully hacked them in to the return statement and they seemed to work, but I'm not sure how I would go about adding them to the prototype template. Thanks again!