Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
373 changes: 373 additions & 0 deletions examples/GeoJSONMarker.ipynb

Large diffs are not rendered by default.

6,627 changes: 6,627 additions & 0 deletions examples/data/subwaystations.geojson

Large diffs are not rendered by default.

48 changes: 44 additions & 4 deletions folium/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
parse_options,
camelize
)
from folium.vector_layers import PolyLine, path_options
from folium.vector_layers import Circle, CircleMarker, PolyLine, path_options

from jinja2 import Template

Expand Down Expand Up @@ -343,6 +343,12 @@ class GeoJson(Layer):
tooltip: GeoJsonTooltip, Tooltip or str, default None
Display a text when hovering over the object. Can utilize the data,
see folium.GeoJsonTooltip for info on how to do that.
popup: GeoJsonPopup, optional
Show a different popup for each feature by passing a GeoJsonPopup object.
marker: Circle, CircleMarker or Marker, optional
If your data contains Point geometry, you can format the markers by passing a Cirle,
CircleMarker or Marker object with your wanted options. The `style_function` and
`highlight_function` will also target the marker object you passed.
embed: bool, default True
Whether to embed the data in the html file or not. Note that disabling
embedding is only supported if you provide a file link or URL.
Expand Down Expand Up @@ -393,21 +399,48 @@ class GeoJson(Layer):
}
}
{%- endif %}

{%- if this.marker %}
function {{ this.get_name() }}_pointToLayer(feature, latlng) {
var opts = {{ this.marker.options | tojson | safe }};
{% if this.marker._name == 'Marker' and this.marker.icon %}
const iconOptions = {{ this.marker.icon.options | tojson | safe }}
const iconRootAlias = L{%- if this.marker.icon._name == "Icon" %}.AwesomeMarkers{%- endif %}
opts.icon = new iconRootAlias.{{ this.marker.icon._name }}(iconOptions)
{% endif %}
{%- if this.style_function %}
let style = {{ this.get_name()}}_styler(feature)
Object.assign({%- if this.marker.icon -%}opts.icon.options{%- else -%} opts {%- endif -%}, style)
{% endif %}
return new L.{{this.marker._name}}(latlng, opts)
}
{%- endif %}

function {{this.get_name()}}_onEachFeature(feature, layer) {
layer.on({
{%- if this.highlight %}
mouseout: function(e) {
{{ this.get_name() }}.resetStyle(e.target);
if(typeof e.target.setStyle === "function"){
{{ this.get_name() }}.resetStyle(e.target);
}
},
mouseover: function(e) {
e.target.setStyle({{ this.get_name() }}_highlighter(e.target.feature));
if(typeof e.target.setStyle === "function"){
const highlightStyle = {{ this.get_name() }}_highlighter(e.target.feature)
e.target.setStyle(highlightStyle);
}
},
{%- endif %}
{%- if this.zoom_on_click %}
click: function(e) {
if (typeof e.target.getBounds === 'function') {
{{ this.parent_map.get_name() }}.fitBounds(e.target.getBounds());
}
else if (typeof e.target.getLatLng === 'function'){
let zoom = {{ this.parent_map.get_name() }}.getZoom()
zoom = zoom > 12 ? zoom : zoom + 1
{{ this.parent_map.get_name() }}.flyTo(e.target.getLatLng(), zoom)
}
}
{%- endif %}
});
Expand All @@ -420,6 +453,9 @@ class GeoJson(Layer):
{% if this.style %}
style: {{ this.get_name() }}_styler,
{%- endif %}
{%- if this.marker %}
pointToLayer: {{ this.get_name() }}_pointToLayer
{%- endif %}
});

function {{ this.get_name() }}_add (data) {
Expand All @@ -440,7 +476,7 @@ class GeoJson(Layer):
def __init__(self, data, style_function=None, highlight_function=None, # noqa
name=None, overlay=True, control=True, show=True,
smooth_factor=None, tooltip=None, embed=True, popup=None,
zoom_on_click=False):
zoom_on_click=False, marker=None):
super(GeoJson, self).__init__(name=name, overlay=overlay,
control=control, show=show)
self._name = 'GeoJson'
Expand All @@ -452,6 +488,10 @@ def __init__(self, data, style_function=None, highlight_function=None, # noqa
self.style = style_function is not None
self.highlight = highlight_function is not None
self.zoom_on_click = zoom_on_click
if marker:
if not isinstance(marker, (Circle, CircleMarker, Marker)):
raise TypeError("Only Marker, Circle, and CircleMarker are supported as GeoJson marker types.")
self.marker = marker

self.data = self.process_data(data)

Expand Down
9 changes: 7 additions & 2 deletions folium/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,18 +270,19 @@ class Marker(MacroElement):
{% endmacro %}
""")

def __init__(self, location, popup=None, tooltip=None, icon=None,
def __init__(self, location=None, popup=None, tooltip=None, icon=None,
draggable=False, **kwargs):
super(Marker, self).__init__()
self._name = 'Marker'
self.location = validate_location(location)
self.location = validate_location(location) if location else None
self.options = parse_options(
draggable=draggable or None,
autoPan=draggable or None,
**kwargs
)
if icon is not None:
self.add_child(icon)
self.icon = icon
if popup is not None:
self.add_child(popup if isinstance(popup, Popup)
else Popup(str(popup)))
Expand All @@ -296,6 +297,10 @@ def _get_self_bounds(self):
"""
return [self.location, self.location]

def render(self):
if self.location is None:
raise ValueError("{} location must be assigned when added directly to map.".format(self._name))
super(Marker, self).render()

class Popup(Element):
"""Create a Popup instance that can be linked to a Layer.
Expand Down
4 changes: 2 additions & 2 deletions folium/vector_layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ class Circle(Marker):
{% endmacro %}
""")

def __init__(self, location, radius, popup=None, tooltip=None, **kwargs):
def __init__(self, location=None, radius=50, popup=None, tooltip=None, **kwargs):
super(Circle, self).__init__(location, popup=popup, tooltip=tooltip)
self._name = 'circle'
self.options = path_options(line=False, radius=radius, **kwargs)
Expand Down Expand Up @@ -300,7 +300,7 @@ class CircleMarker(Marker):
{% endmacro %}
""")

def __init__(self, location, radius=10, popup=None, tooltip=None, **kwargs):
def __init__(self, location=None, radius=10, popup=None, tooltip=None, **kwargs):
super(CircleMarker, self).__init__(location, popup=popup,
tooltip=tooltip)
self._name = 'CircleMarker'
Expand Down
Loading