initial commit
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
from branca.element import MacroElement
|
||||
from jinja2 import Template
|
||||
|
||||
from folium import Map
|
||||
from folium.elements import JSCSSMixin
|
||||
from folium.features import FeatureGroup, GeoJson, TopoJson
|
||||
from folium.plugins import MarkerCluster
|
||||
from folium.utilities import parse_options
|
||||
|
||||
|
||||
class Search(JSCSSMixin, MacroElement):
|
||||
"""
|
||||
Adds a search tool to your map.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
layer: GeoJson, TopoJson, FeatureGroup, MarkerCluster class object.
|
||||
The map layer to index in the Search view.
|
||||
search_label: str, optional
|
||||
'properties' key in layer to index Search, if layer is GeoJson/TopoJson.
|
||||
search_zoom: int, optional
|
||||
Zoom level to set the map to on match.
|
||||
By default zooms to Polygon/Line bounds and points
|
||||
on their natural extent.
|
||||
geom_type: str, default 'Point'
|
||||
Feature geometry type. "Point", "Line" or "Polygon"
|
||||
position: str, default 'topleft'
|
||||
Change the position of the search bar, can be:
|
||||
'topleft', 'topright', 'bottomright' or 'bottomleft',
|
||||
placeholder: str, default 'Search'
|
||||
Placeholder text inside the Search box if nothing is entered.
|
||||
collapsed: boolean, default False
|
||||
Whether the Search box should be collapsed or not.
|
||||
**kwargs.
|
||||
Assorted style options to change feature styling on match.
|
||||
Use the same way as vector layer arguments.
|
||||
|
||||
See https://github.com/stefanocudini/leaflet-search for more information.
|
||||
|
||||
"""
|
||||
|
||||
_template = Template(
|
||||
"""
|
||||
{% macro script(this, kwargs) %}
|
||||
var {{this.layer.get_name()}}searchControl = new L.Control.Search({
|
||||
layer: {{this.layer.get_name()}},
|
||||
{% if this.search_label %}
|
||||
propertyName: '{{this.search_label}}',
|
||||
{% endif %}
|
||||
collapsed: {{this.collapsed|tojson|safe}},
|
||||
textPlaceholder: '{{this.placeholder}}',
|
||||
position:'{{this.position}}',
|
||||
{% if this.geom_type == 'Point' %}
|
||||
initial: false,
|
||||
{% if this.search_zoom %}
|
||||
zoom: {{this.search_zoom}},
|
||||
{% endif %}
|
||||
hideMarkerOnCollapse: true
|
||||
{% else %}
|
||||
marker: false,
|
||||
moveToLocation: function(latlng, title, map) {
|
||||
var zoom = {% if this.search_zoom %} {{ this.search_zoom }} {% else %} map.getBoundsZoom(latlng.layer.getBounds()) {% endif %}
|
||||
map.flyTo(latlng, zoom); // access the zoom
|
||||
}
|
||||
{% endif %}
|
||||
});
|
||||
{{this.layer.get_name()}}searchControl.on('search:locationfound', function(e) {
|
||||
{{this.layer.get_name()}}.setStyle(function(feature){
|
||||
return feature.properties.style
|
||||
})
|
||||
{% if this.options %}
|
||||
e.layer.setStyle({{ this.options|tojson }});
|
||||
{% endif %}
|
||||
if(e.layer._popup)
|
||||
e.layer.openPopup();
|
||||
})
|
||||
{{this.layer.get_name()}}searchControl.on('search:collapsed', function(e) {
|
||||
{{this.layer.get_name()}}.setStyle(function(feature){
|
||||
return feature.properties.style
|
||||
});
|
||||
});
|
||||
{{this._parent.get_name()}}.addControl( {{this.layer.get_name()}}searchControl );
|
||||
|
||||
{% endmacro %}
|
||||
""" # noqa
|
||||
)
|
||||
|
||||
default_js = [
|
||||
(
|
||||
"Leaflet.Search.js",
|
||||
"https://cdn.jsdelivr.net/npm/leaflet-search@2.9.7/dist/leaflet-search.min.js",
|
||||
)
|
||||
]
|
||||
default_css = [
|
||||
(
|
||||
"Leaflet.Search.css",
|
||||
"https://cdn.jsdelivr.net/npm/leaflet-search@2.9.7/dist/leaflet-search.min.css",
|
||||
)
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
layer,
|
||||
search_label=None,
|
||||
search_zoom=None,
|
||||
geom_type="Point",
|
||||
position="topleft",
|
||||
placeholder="Search",
|
||||
collapsed=False,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__()
|
||||
assert isinstance(layer, (GeoJson, MarkerCluster, FeatureGroup, TopoJson)), (
|
||||
"Search can only index FeatureGroup, "
|
||||
"MarkerCluster, GeoJson, and TopoJson layers at "
|
||||
"this time."
|
||||
)
|
||||
self.layer = layer
|
||||
self.search_label = search_label
|
||||
self.search_zoom = search_zoom
|
||||
self.geom_type = geom_type
|
||||
self.position = position
|
||||
self.placeholder = placeholder
|
||||
self.collapsed = collapsed
|
||||
self.options = parse_options(**kwargs)
|
||||
|
||||
def test_params(self, keys):
|
||||
if keys is not None and self.search_label is not None:
|
||||
assert self.search_label in keys, (
|
||||
f"The label '{self.search_label}' was not " f"available in {keys}" ""
|
||||
)
|
||||
assert isinstance(
|
||||
self._parent, Map
|
||||
), "Search can only be added to folium Map objects."
|
||||
|
||||
def render(self, **kwargs):
|
||||
if isinstance(self.layer, GeoJson):
|
||||
keys = tuple(self.layer.data["features"][0]["properties"].keys())
|
||||
elif isinstance(self.layer, TopoJson):
|
||||
obj_name = self.layer.object_path.split(".")[-1]
|
||||
keys = tuple(
|
||||
self.layer.data["objects"][obj_name]["geometries"][0][
|
||||
"properties"
|
||||
].keys()
|
||||
) # noqa
|
||||
else:
|
||||
keys = None
|
||||
self.test_params(keys=keys)
|
||||
|
||||
super().render(**kwargs)
|
||||
Reference in New Issue
Block a user