2017-09-14 18:08:13 +00:00
|
|
|
function getBoundsWithPadding(map, padding) {
|
|
|
|
const bounds = map.getPixelBounds(),
|
|
|
|
sw = map.unproject(bounds.getBottomLeft().add([-padding, padding])),
|
|
|
|
ne = map.unproject(bounds.getTopRight().add([padding, -padding]));
|
|
|
|
|
|
|
|
return new L.LatLngBounds(sw, ne);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object.assign(L.LatLngBounds.prototype, {
|
|
|
|
toMinMax: function() {
|
|
|
|
return {
|
|
|
|
minX: this.getWest(),
|
|
|
|
minY: this.getSouth(),
|
|
|
|
maxX: this.getEast(),
|
|
|
|
maxY: this.getNorth()
|
|
|
|
};
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
L.LayerGroup.include({
|
|
|
|
updateLayers: function(layers) {
|
|
|
|
var _layers = {};
|
|
|
|
|
|
|
|
for (var i = 0; i < layers.length; ++i)
|
|
|
|
_layers[this.getLayerId(layers[i])] = layers[i];
|
|
|
|
|
|
|
|
var toRemove = [];
|
|
|
|
|
|
|
|
for (var id in this._layers) {
|
|
|
|
if (!(id in _layers))
|
|
|
|
toRemove.push(this._layers[id]);
|
|
|
|
}
|
|
|
|
|
|
|
|
toRemove.forEach(this.removeLayer, this);
|
|
|
|
|
|
|
|
for (var id in _layers) {
|
|
|
|
if (!(id in this._layers))
|
|
|
|
this.addLayer(_layers[id]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
L.IndexedFeatureLayer = L.GeoJSON.extend({
|
|
|
|
options: {
|
|
|
|
padding: 30 // in pixels
|
|
|
|
},
|
|
|
|
|
|
|
|
initialize: function (geojson, options) {
|
|
|
|
L.Util.setOptions(this, options);
|
|
|
|
|
|
|
|
this._layers = {};
|
|
|
|
|
|
|
|
this._visible = L.layerGroup([]);
|
|
|
|
|
|
|
|
this._rbush = rbush(9);
|
|
|
|
|
|
|
|
if (geojson) {
|
|
|
|
this.addData(geojson);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
search: function(bounds) {
|
|
|
|
return this._rbush.search(bounds.toMinMax()).map(result => result.layer);
|
|
|
|
},
|
|
|
|
|
|
|
|
getLayerId: function(layer) {
|
|
|
|
return layer.feature.id;
|
|
|
|
},
|
|
|
|
|
|
|
|
addLayer: function (layer) {
|
|
|
|
const id = this.getLayerId(layer);
|
|
|
|
|
|
|
|
if (id in this._layers)
|
|
|
|
return this;
|
|
|
|
|
|
|
|
this._layers[id] = layer;
|
|
|
|
|
|
|
|
// Necessary for circle markers I use here
|
|
|
|
layer._map = this._map;
|
|
|
|
layer._project();
|
|
|
|
|
|
|
|
const xy = layer.getBounds().toMinMax();
|
|
|
|
this._rbush.insert(Object.assign({layer: layer}, xy));
|
|
|
|
|
|
|
|
if (this._map
|
|
|
|
&& !this._visible.hasLayer(layer)
|
|
|
|
&& this._layerInView(layer)) {
|
|
|
|
layer._map = null;
|
|
|
|
this._visible.addLayer(layer);
|
|
|
|
} else {
|
|
|
|
layer._map = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
onAdd: function (map) {
|
|
|
|
this._visible.addTo(map);
|
|
|
|
map.on('moveend', this._redraw, this);
|
|
|
|
this._redraw();
|
|
|
|
},
|
|
|
|
|
|
|
|
onRemove: function(map) {
|
|
|
|
this._visible.removeFrom(map);
|
|
|
|
},
|
|
|
|
|
2017-09-15 09:44:50 +00:00
|
|
|
eachVisibleLayer: function(callback) {
|
|
|
|
return this._visible.eachLayer(callback);
|
|
|
|
},
|
|
|
|
|
2017-09-14 18:08:13 +00:00
|
|
|
_getBounds: function() {
|
|
|
|
return getBoundsWithPadding(this._map, this.options.padding);
|
|
|
|
},
|
|
|
|
|
|
|
|
_redraw: function() {
|
|
|
|
const layers = this.search(this._getBounds());
|
|
|
|
this._visible.updateLayers(layers);
|
|
|
|
},
|
|
|
|
|
|
|
|
_layerInView: function(layer) {
|
|
|
|
return layer.getBounds().intersects(this._getBounds());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
L.indexedGeoJSON = function(geojson, options) {
|
|
|
|
return new L.IndexedFeatureLayer(geojson, options);
|
|
|
|
};
|