Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
95a8c0f
Break folium.py and start plugging Elements
Sep 7, 2015
c6acba2
Fix test_simple_marker
Sep 7, 2015
988621b
Fix test_div_markers
Sep 7, 2015
c91801a
Fix test_circle_marker
Sep 7, 2015
cf27f98
Fix test_poly_marker
Sep 7, 2015
92a851c
Fix test_latlng_pop
Sep 7, 2015
5eec84b
Fix test_click_for_marker
Sep 7, 2015
98b1d41
Fix test_vega_popup
Sep 7, 2015
b7ae4cc
cleanup simple_popup.js
Sep 7, 2015
3ef2658
Fix py3 OrderedDict.values() specificity
Sep 7, 2015
2311b9f
geo_json replacement
Sep 9, 2015
e012257
Merge branch 'master' into elements
Sep 11, 2015
b0fb739
Split test_folium.geo_json
Sep 14, 2015
6dc60f7
Fix test_geo_json_simple
Sep 14, 2015
55fe18f
Un-indent color_scale template
Sep 14, 2015
6832e24
Fix test_geo_json_bad*
Sep 14, 2015
ff8785d
Fix test_geo_json_data_binding
Sep 29, 2015
0154a4c
Fix test_topo_json
Sep 29, 2015
d401e4b
Fix test_build_map
Sep 29, 2015
c9548ba
Fix test_tile_attr_unicode
Sep 29, 2015
2431c51
Fix test_create_map
Sep 29, 2015
80be994
Fix test_line
Sep 30, 2015
00a1dfe
Fix path issue in test_topo_json
Sep 30, 2015
0d2eece
Fix test_multi_polyline
Sep 30, 2015
4c1515d
Fix test_fit_bounds
Sep 30, 2015
c3ede82
Fix test_image_overlay
Oct 1, 2015
14b3671
Fix python3 stuff in test_image_overlay
Oct 1, 2015
a6a0c3c
Remove test_scroll_zoom_toggler and test_marker_cluster -> to plugins
Oct 3, 2015
859d7b8
Fix test_marker_cluster
Oct 3, 2015
121508a
Fix test_scroll_zoom_toggler
Oct 3, 2015
bcf573e
Fix python3 bug with base64 encode
Oct 3, 2015
75cac11
Fix test_terminator
Oct 3, 2015
8d5dd69
Fix test_boat_marker
Oct 4, 2015
7dd3fb8
Fix test_layer
Oct 4, 2015
f6edd35
Fix test_timestamp_geo_json
Oct 4, 2015
1831159
Removed test_plugins.test_geojson <= duplicate
Oct 4, 2015
5d665c5
Cleanup useless things
Oct 4, 2015
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
3 changes: 2 additions & 1 deletion folium/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
ENV = Environment(loader=PackageLoader('folium', 'templates'))
from collections import OrderedDict
import json
import base64

from .six import urlopen
from .utilities import _camelify, _parse_size
Expand Down Expand Up @@ -266,7 +267,7 @@ def _repr_html_(self, **kwargs):

iframe = '<iframe src="{html}" width="{width}px" height="{height}px"></iframe>'\
.format(\
html = "data:text/html;base64,"+html.encode('utf8').encode('base64'),
html = b"data:text/html;base64,"+base64.b64encode(html.encode('utf8')),
#html = self.HTML.replace('"','&quot;'),
width = int(60.*width),
height= int(60.*height),
Expand Down
376 changes: 349 additions & 27 deletions folium/features.py

Large diffs are not rendered by default.

991 changes: 236 additions & 755 deletions folium/folium.py

Large diffs are not rendered by default.

100 changes: 98 additions & 2 deletions folium/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
Classes for drawing maps.
"""
import warnings
import json
from collections import OrderedDict

from jinja2 import Template

Expand Down Expand Up @@ -85,6 +87,8 @@ def __init__(self, location=None, width='100%', height='100%',
self.location = location
self.zoom_start = zoom_start

Figure().add_children(self)

# Map Size Parameters.
self.width = _parse_size(width)
self.height = _parse_size(height)
Expand All @@ -108,6 +112,7 @@ def __init__(self, location=None, width='100%', height='100%',
height: {{this.height[0]}}{{this.height[1]}};
left: {{this.left[0]}}{{this.left[1]}};
top: {{this.top[0]}}{{this.top[1]}};
}
</style>
{% endmacro %}
{% macro html(this, kwargs) %}
Expand Down Expand Up @@ -169,7 +174,7 @@ def add_tile_layer(self, tiles='OpenStreetMap', name=None,

class TileLayer(MacroElement):
def __init__(self, tiles='OpenStreetMap', name=None,
min_zoom=1, max_zoom=18, attr=None, API_key=None):
min_zoom=1, max_zoom=18, attr=None, API_key=None, overlay = False):
"""TODO docstring here
Parameters
----------
Expand All @@ -181,6 +186,8 @@ def __init__(self, tiles='OpenStreetMap', name=None,
self.min_zoom = min_zoom
self.max_zoom = max_zoom

self.overlay = overlay

self.tiles = ''.join(tiles.lower().strip().split())
if self.tiles in ('cloudmade', 'mapbox') and not API_key:
raise ValueError('You must pass an API key if using Cloudmade'
Expand All @@ -197,6 +204,8 @@ def __init__(self, tiles='OpenStreetMap', name=None,
if not attr:
raise ValueError('Custom tiles must'
' also be passed an attribution')
if isinstance(attr, binary_type):
attr = text_type(attr, 'utf8')
self.attr = attr

self._template = Template(u"""
Expand All @@ -213,6 +222,42 @@ def __init__(self, tiles='OpenStreetMap', name=None,
{% endmacro %}
""")

class LayerControl(MacroElement):
"""Adds a layer control to the map."""
def __init__(self):
"""Creates a LayerControl object to be added on a folium map.

Parameters
----------
"""
super(LayerControl, self).__init__()
self._name = 'LayerControl'

self.base_layers = OrderedDict()
self.overlays = OrderedDict()

self._template = Template("""
{% macro script(this,kwargs) %}
var {{this.get_name()}} = {
base_layers : { {% for key,val in this.base_layers.items() %}"{{key}}" : {{val}},{% endfor %} },
overlays : { {% for key,val in this.overlays.items() %}"{{key}}" : {{val}},{% endfor %} }
};
L.control.layers(
{{this.get_name()}}.base_layers,
{{this.get_name()}}.overlays
).addTo({{this._parent.get_name()}});
{% endmacro %}
""")

def render(self, **kwargs):
"""TODO : docstring here."""
self.base_layers = OrderedDict([(val.tile_name,val.get_name()) \
for key,val in self._parent._children.items() if isinstance(val,TileLayer) and not val.overlay])
self.overlays = OrderedDict([(val.tile_name,val.get_name()) \
for key,val in self._parent._children.items() if isinstance(val,TileLayer) and val.overlay])

super(LayerControl, self).render()

class Icon(MacroElement):
def __init__(self, color='blue', icon='info-sign', angle=0):
"""TODO : docstring here"""
Expand Down Expand Up @@ -265,6 +310,10 @@ def __init__(self, location, popup=None, icon=None):
super(Marker, self).__init__()
self._name = 'Marker'
self.location = location
if icon is not None:
self.add_children(icon)
if popup is not None:
self.add_children(popup)

self._template = Template(u"""
{% macro script(this, kwargs) %}
Expand Down Expand Up @@ -292,7 +341,7 @@ def __init__(self, html, max_width=300):
self.script._parent = self

if isinstance(html, Element):
self.html.add_children(html)
self.add_children(html)
elif isinstance(html, text_type) or isinstance(html,binary_type):
self.html.add_children(Html(text_type(html)))

Expand Down Expand Up @@ -324,3 +373,50 @@ def render(self, **kwargs):

figure.script.add_children(Element(\
self._template.render(this=self, kwargs=kwargs)), name=self.get_name())

class FitBounds(MacroElement):
def __init__(self, bounds, padding_top_left=None,
padding_bottom_right=None, padding=None, max_zoom=None):
"""Fit the map to contain a bounding box with the maximum zoom level possible.

Parameters
----------
bounds: list of (latitude, longitude) points
Bounding box specified as two points [southwest, northeast]
padding_top_left: (x, y) point, default None
Padding in the top left corner. Useful if some elements in
the corner, such as controls, might obscure objects you're zooming
to.
padding_bottom_right: (x, y) point, default None
Padding in the bottom right corner.
padding: (x, y) point, default None
Equivalent to setting both top left and bottom right padding to
the same value.
max_zoom: int, default None
Maximum zoom to be used.

"""
super(FitBounds, self).__init__()
self._name = 'FitBounds'
self.bounds = json.loads(json.dumps(bounds))
options = {
'maxZoom': max_zoom,
'paddingTopLeft': padding_top_left,
'paddingBottomRight': padding_bottom_right,
'padding': padding,
}
self.fit_bounds_options = json.dumps({key:val for key,val in options.items() if val},
sort_keys=True)

self._template = Template(u"""
{% macro script(this, kwargs) %}
{% if this.autobounds %}
var autobounds = L.featureGroup({{ this.features }}).getBounds()
{% endif %}

{{this._parent.get_name()}}.fitBounds(
{% if this.bounds %}{{ this.bounds }}{% else %}"autobounds"{% endif %},
{{ this.fit_bounds_options }}
);
{% endmacro %}
""")
2 changes: 0 additions & 2 deletions folium/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@
from .scroll_zoom_toggler import ScrollZoomToggler
from .terminator import Terminator
from .boat_marker import BoatMarker
from .layer import Layer, LayerControl
from .geo_json import GeoJson
from .timestamped_geo_json import TimestampedGeoJson
49 changes: 24 additions & 25 deletions folium/plugins/boat_marker.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
Creates a marker shaped like a boat. Optionally you can append a wind direction.
"""
import json
from jinja2 import Template

from .plugin import Plugin
from folium.element import JavascriptLink, MacroElement, Figure

class BoatMarker(Plugin):
class BoatMarker(MacroElement):
"""Adds a BoatMarker layer on the map."""
def __init__(self, position=None, heading=0, wind_heading=None, wind_speed=0, **kwargs):
"""Creates a BoatMarker plugin to append into a map with
Expand All @@ -32,30 +33,28 @@ def __init__(self, position=None, heading=0, wind_heading=None, wind_speed=0, **
Speed of the wind in knots.
"""
super(BoatMarker, self).__init__()
self.plugin_name = 'BoatMarker'
self._name = 'BoatMarker'
self.position = None if position is None else tuple(position)
self.heading = heading
self.wind_heading = wind_heading
self.wind_speed = wind_speed
self.kwargs = kwargs.copy()

def render_header(self, nb):
"""Generates the HTML part of the plugin."""
return """
<script src="https://thomasbrueggemann.github.io/leaflet.boatmarker/js/leaflet.boatmarker.min.js"></script>
""" if nb==0 else ""

def render_js(self, nb):
"""Generates the Javascript part of the plugin."""
kwargs_str = "{%s}" % ",".join(["%s : %s" % (key,json.dumps(val)) for (key,val) in self.kwargs.items()])
position_str = "map.getCenter()" if self.position is None else "[%.12f,%.12f]"%self.position
out = 'var boatMarker_%s = L.boatMarker(%s, %s).addTo(map);' % (nb,position_str,kwargs_str)

if self.wind_heading is None:
out += "boatMarker_%s.setHeading(%s);" % (nb,int(self.heading))
else:
out += "boatMarker_%s.setHeadingWind(%s, %s, %s);"%(nb,int(self.heading),
int(self.wind_speed),
int(self.wind_heading),
)
return out
self.kwargs = json.dumps(kwargs)

self._template = Template(u"""
{% macro script(this, kwargs) %}
var {{this.get_name()}} = L.boatMarker(
[{{this.position[0]}},{{this.position[1]}}],
{{this.kwargs}}).addTo({{this._parent.get_name()}});
{{this.get_name()}}.setHeadingWind({{this.heading}}, {{this.wind_speed}}, {{this.wind_heading}});
{% endmacro %}
""")
def render(self,**kwargs):
super(BoatMarker,self).render(**kwargs)

figure = self.get_root()
assert isinstance(figure,Figure), ("You cannot render this Element "
"if it's not in a Figure.")

figure.header.add_children(\
JavascriptLink("https://thomasbrueggemann.github.io/leaflet.boatmarker/js/leaflet.boatmarker.min.js"),
name='markerclusterjs')
50 changes: 0 additions & 50 deletions folium/plugins/geo_json.py

This file was deleted.

77 changes: 0 additions & 77 deletions folium/plugins/layer.py

This file was deleted.

6 changes: 0 additions & 6 deletions folium/plugins/leaflet-dvf.markers.min.js

This file was deleted.

Loading