New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding popup_attribute to the GeoJson feature #376
Changes from all commits
14da52e
0c2429c
3747c56
0729193
874aefd
54bf3dc
828d0f1
3f8ff48
abca6b5
bcb72b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,8 @@ | |
|
||
Extra features Elements. | ||
""" | ||
from types import FunctionType | ||
|
||
from jinja2 import Template | ||
import json | ||
|
||
|
@@ -267,6 +269,11 @@ class GeoJson(Layer): | |
* If str, then data will be passed to the JavaScript as-is. | ||
style_function: function, default None | ||
A function mapping a GeoJson Feature to a style dict. | ||
popup_function: string or function, default None | ||
The popup value for the feature | ||
* If string, then an attribute to use as a popup value for the feature | ||
* If function, a function taking a GeoJson Feature and returning a | ||
html string to be used as the popup | ||
name : string, default None | ||
The name of the Layer, as it will appear in LayerControls | ||
overlay : bool, default False | ||
|
@@ -290,9 +297,17 @@ class GeoJson(Layer): | |
... x['properties']['name']=='Alabama' else | ||
... '#00ff00'} | ||
>>> GeoJson(geojson, style_function=style_function) | ||
|
||
>>> # Provide a popup using the name attribute of each feature. | ||
>>> GeoJson(geojson, popup_function='name') | ||
|
||
>>> # Provide a popup based on the output of a function on each feature | ||
>>> GeoJson( | ||
... geojson, | ||
... popup_function=lambda feautre: feautre['properties']['name']) | ||
""" | ||
def __init__(self, data, style_function=None, name=None, | ||
overlay=True, control=True): | ||
def __init__(self, data, style_function=None, popup_function=None, | ||
name=None, overlay=True, control=True): | ||
super(GeoJson, self).__init__(name=name, overlay=overlay, | ||
control=control) | ||
self._name = 'GeoJson' | ||
|
@@ -328,15 +343,58 @@ def style_function(x): | |
return {} | ||
self.style_function = style_function | ||
|
||
self._popup_function = None | ||
self.popup_attribute = None | ||
self.popup_function = popup_function # Set the popup function | ||
|
||
self._template = Template(u""" | ||
{% macro script(this, kwargs) %} | ||
{% if this.popup_attribute or this.popup_function %} | ||
function {{this.get_name()}}_EachFeature(feature, layer) { | ||
if (feature.properties && feature.properties.{{this.popup_attribute}}) { | ||
layer.bindPopup(feature.properties.{{this.popup_attribute}}); | ||
} | ||
} | ||
{% endif %} | ||
var {{this.get_name()}} = L.geoJson( | ||
{% if this.embed %}{{this.style_data()}}{% else %}"{{this.data}}"{% endif %}) | ||
{% if this.embed %}{{this.style_data()}}{% else %}"{{this.data}}"{% endif %}, | ||
{{'{'}} | ||
{% if this.popup_attribute or this.popup_function %} | ||
onEachFeature: {{this.get_name()}}_EachFeature | ||
{% endif %} | ||
{{'}'}} | ||
) | ||
.addTo({{this._parent.get_name()}}); | ||
{{this.get_name()}}.setStyle(function(feature) {return feature.properties.style;}); | ||
{% endmacro %} | ||
""") # noqa | ||
|
||
@property | ||
def popup_function(self): | ||
return self._popup_function | ||
|
||
@popup_function.setter | ||
def popup_function(self, func): | ||
""" | ||
Use a setter so that if the dev sets the property function after the | ||
fact the `popup_attribute` is set correctly. | ||
|
||
Parameters | ||
---------- | ||
func : srting, function or None | ||
The popup value for the feature | ||
* If string, then an attribute to use as a popup value for the feature | ||
* If function, a function taking a GeoJson Feature and returning a | ||
html string to be used as the popup | ||
""" | ||
if isinstance(func, FunctionType): | ||
self.popup_attribute = "_popupContent" | ||
elif isinstance(func, text_type): | ||
self.popup_attribute = func | ||
elif isinstance(func, binary_type): | ||
self.popup_attribute = text_type(func, 'utf8') | ||
self._popup_function = func | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is great, but it seems complicated to a dummy programmer like me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, no reason not to. I'll update the code. It's easy to move the check into the render function. |
||
def style_data(self): | ||
""" | ||
Applies `self.style_function` to each feature of `self.data` and | ||
|
@@ -352,6 +410,13 @@ def style_data(self): | |
|
||
for feature in self.data['features']: | ||
feature.setdefault('properties', {}).setdefault('style', {}).update(self.style_function(feature)) # noqa | ||
|
||
try: | ||
for feature in self.data["features"]: | ||
feature["properties"]["_popupContent"] = self.popup_function(feature) # noqa | ||
except TypeError: | ||
pass | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you need a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the checks on the function are outside the render operation, I was being a bit slack and letting the function fail when it wasn't a function. I'll move checks inside the loop. |
||
return json.dumps(self.data, sort_keys=True) | ||
|
||
def _get_self_bounds(self): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E501 line too long (82 > 79 characters)