Last active
September 23, 2016 16:13
-
-
Save pospi/85c31530c4a93cf091ce to your computer and use it in GitHub Desktop.
Handle multiple geoJSON layers in a Leaflet.js angular directive
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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; | |
} | |
]); |
@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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 anonEachFeature
option. The key is probably that myonEachFeature
is a generator function that returns a new function for every layer it's initialised on:You can then create different logic for your layers by switching on
theLayer
. Hope that helps a little bit!