Skip to content

Commit be35c52

Browse files
authored
Merge pull request #669 from ocefpaf/measure_distance
Implement measure plugin closes #472
2 parents a2494a8 + 542f5fd commit be35c52

4 files changed

Lines changed: 160 additions & 7 deletions

File tree

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
0.4.0
22
~~~~~
3+
- Added `MeasureControl` (ocefpaf #669)
34
- Added `VideoOverlay` plugin (ocefpaf #665)
45
- Added `TimestampedWmsTileLayers` plugin (acrosby #644 and #660)
56
- Vega-Lite features support via altair (njwilson23 #643)

examples/MeasureControl.ipynb

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"metadata": {},
7+
"outputs": [
8+
{
9+
"name": "stdout",
10+
"output_type": "stream",
11+
"text": [
12+
"0.3.0+129.gf25ca84.dirty\n"
13+
]
14+
}
15+
],
16+
"source": [
17+
"import folium\n",
18+
"\n",
19+
"print(folium.__version__)"
20+
]
21+
},
22+
{
23+
"cell_type": "code",
24+
"execution_count": 2,
25+
"metadata": {},
26+
"outputs": [
27+
{
28+
"data": {
29+
"text/html": [
30+
"<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><iframe src=\"data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgPHNjcmlwdD5MX1BSRUZFUl9DQU5WQVMgPSBmYWxzZTsgTF9OT19UT1VDSCA9IGZhbHNlOyBMX0RJU0FCTEVfM0QgPSBmYWxzZTs8L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4xLjAvZGlzdC9sZWFmbGV0LmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2FqYXguZ29vZ2xlYXBpcy5jb20vYWpheC9saWJzL2pxdWVyeS8xLjExLjEvanF1ZXJ5Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvanMvYm9vdHN0cmFwLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuanMiPjwvc2NyaXB0PgogICAgPHNjcmlwdCBzcmM9Imh0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL2xlYWZsZXQubWFya2VyY2x1c3Rlci8xLjAuMC9sZWFmbGV0Lm1hcmtlcmNsdXN0ZXItc3JjLmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9sZWFmbGV0Lm1hcmtlcmNsdXN0ZXIvMS4wLjAvbGVhZmxldC5tYXJrZXJjbHVzdGVyLmpzIj48L3NjcmlwdD4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9sZWFmbGV0QDEuMS4wL2Rpc3QvbGVhZmxldC5jc3MiIC8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vYm9vdHN0cmFwLzMuMi4wL2Nzcy9ib290c3RyYXAubWluLmNzcyIgLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvY3NzL2Jvb3RzdHJhcC10aGVtZS5taW4uY3NzIiAvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2ZvbnQtYXdlc29tZS80LjYuMy9jc3MvZm9udC1hd2Vzb21lLm1pbi5jc3MiIC8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL0xlYWZsZXQuYXdlc29tZS1tYXJrZXJzLzIuMC4yL2xlYWZsZXQuYXdlc29tZS1tYXJrZXJzLmNzcyIgLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbGVhZmxldC5tYXJrZXJjbHVzdGVyLzEuMC4wL01hcmtlckNsdXN0ZXIuRGVmYXVsdC5jc3MiIC8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL2xlYWZsZXQubWFya2VyY2x1c3Rlci8xLjAuMC9NYXJrZXJDbHVzdGVyLmNzcyIgLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9yYXdnaXQuY29tL3B5dGhvbi12aXN1YWxpemF0aW9uL2ZvbGl1bS9tYXN0ZXIvZm9saXVtL3RlbXBsYXRlcy9sZWFmbGV0LmF3ZXNvbWUucm90YXRlLmNzcyIgLz4KICAgIDxzdHlsZT5odG1sLCBib2R5IHt3aWR0aDogMTAwJTtoZWlnaHQ6IDEwMCU7bWFyZ2luOiAwO3BhZGRpbmc6IDA7fTwvc3R5bGU+CiAgICA8c3R5bGU+I21hcCB7cG9zaXRpb246YWJzb2x1dGU7dG9wOjA7Ym90dG9tOjA7cmlnaHQ6MDtsZWZ0OjA7fTwvc3R5bGU+CiAgICAKICAgICAgICAgICAgPHN0eWxlPiAjbWFwXzdlNWZiZGZhNWVjNzQ5ZjNiZjRkYmMyZWRiNjg3NDI4IHsKICAgICAgICAgICAgICAgIHBvc2l0aW9uIDogcmVsYXRpdmU7CiAgICAgICAgICAgICAgICB3aWR0aCA6IDEwMC4wJTsKICAgICAgICAgICAgICAgIGhlaWdodDogMTAwLjAlOwogICAgICAgICAgICAgICAgbGVmdDogMC4wJTsKICAgICAgICAgICAgICAgIHRvcDogMC4wJTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgPC9zdHlsZT4KICAgICAgICAKICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5yYXdnaXQuY29tL2xqYWdpcy9sZWFmbGV0LW1lYXN1cmUvMi4xLjcvZGlzdC9sZWFmbGV0LW1lYXN1cmUuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2Nkbi5yYXdnaXQuY29tL2xqYWdpcy9sZWFmbGV0LW1lYXN1cmUvMi4xLjcvZGlzdC9sZWFmbGV0LW1lYXN1cmUuY3NzIiAvPgo8L2hlYWQ+Cjxib2R5PiAgICAKICAgIAogICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb2xpdW0tbWFwIiBpZD0ibWFwXzdlNWZiZGZhNWVjNzQ5ZjNiZjRkYmMyZWRiNjg3NDI4IiA+PC9kaXY+CiAgICAgICAgCjwvYm9keT4KPHNjcmlwdD4gICAgCiAgICAKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIHNvdXRoV2VzdCA9IEwubGF0TG5nKC05MCwgLTE4MCk7CiAgICAgICAgICAgICAgICB2YXIgbm9ydGhFYXN0ID0gTC5sYXRMbmcoOTAsIDE4MCk7CiAgICAgICAgICAgICAgICB2YXIgYm91bmRzID0gTC5sYXRMbmdCb3VuZHMoc291dGhXZXN0LCBub3J0aEVhc3QpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIHZhciBtYXBfN2U1ZmJkZmE1ZWM3NDlmM2JmNGRiYzJlZGI2ODc0MjggPSBMLm1hcCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdtYXBfN2U1ZmJkZmE1ZWM3NDlmM2JmNGRiYzJlZGI2ODc0MjgnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge2NlbnRlcjogWy0yNy41NzE3LC00OC42MjU2XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHpvb206IDEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4Qm91bmRzOiBib3VuZHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXllcnM6IFtdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ybGRDb3B5SnVtcDogZmFsc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcnM6IEwuQ1JTLkVQU0czODU3CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgdGlsZV9sYXllcl8xM2NlMGZhZjMwYjQ0NThmOWYyNTQ0ZTU1Yjc1YjE1YyA9IEwudGlsZUxheWVyKAogICAgICAgICAgICAgICAgJ2h0dHBzOi8ve3N9LnRpbGUub3BlbnN0cmVldG1hcC5vcmcve3p9L3t4fS97eX0ucG5nJywKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBtYXhab29tOiAxOCwKICAgICAgICAgICAgICAgICAgICBtaW5ab29tOiAxLAogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVvdXNXb3JsZDogZmFsc2UsCiAgICAgICAgICAgICAgICAgICAgbm9XcmFwOiBmYWxzZSwKICAgICAgICAgICAgICAgICAgICBhdHRyaWJ1dGlvbjogJ0RhdGEgYnkgPGEgaHJlZj0iaHR0cDovL29wZW5zdHJlZXRtYXAub3JnIj5PcGVuU3RyZWV0TWFwPC9hPiwgdW5kZXIgPGEgaHJlZj0iaHR0cDovL3d3dy5vcGVuc3RyZWV0bWFwLm9yZy9jb3B5cmlnaHQiPk9EYkw8L2E+LicsCiAgICAgICAgICAgICAgICAgICAgZGV0ZWN0UmV0aW5hOiBmYWxzZSwKICAgICAgICAgICAgICAgICAgICBzdWJkb21haW5zOiAnYWJjJwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwXzdlNWZiZGZhNWVjNzQ5ZjNiZjRkYmMyZWRiNjg3NDI4KTsKCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIG1lYXN1cmVfY29udHJvbF8xYTJkZWU5NTI4Y2I0YTc4YWZhMjcyNjY2MTYxMGU2YyA9IG5ldyBMLkNvbnRyb2wuTWVhc3VyZSgKICAgICAgICAgICAgeyJwb3NpdGlvbiI6ICJ0b3ByaWdodCIsICJwcmltYXJ5TGVuZ3RoVW5pdCI6ICJtZXRlcnMiLCAic2Vjb25kYXJ5TGVuZ3RoVW5pdCI6ICJtaWxlcyIsICJwcmltYXJ5QXJlYVVuaXQiOiAic3FtZXRlcnMiLCAic2Vjb25kYXJ5QXJlYVVuaXQiOiAiYWNyZXMifSk7CiAgICAgICAgICAgIG1hcF83ZTVmYmRmYTVlYzc0OWYzYmY0ZGJjMmVkYjY4NzQyOC5hZGRDb250cm9sKG1lYXN1cmVfY29udHJvbF8xYTJkZWU5NTI4Y2I0YTc4YWZhMjcyNjY2MTYxMGU2Yyk7CgogICAgICAgIAo8L3NjcmlwdD4=\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
31+
],
32+
"text/plain": [
33+
"<folium.folium.Map at 0x7f27dcffcb38>"
34+
]
35+
},
36+
"execution_count": 2,
37+
"metadata": {},
38+
"output_type": "execute_result"
39+
}
40+
],
41+
"source": [
42+
"from folium.plugins import MeasureControl\n",
43+
"\n",
44+
"m = folium.Map([-27.5717, -48.6256], zoom_start=10)\n",
45+
"\n",
46+
"m.add_child(MeasureControl())\n",
47+
"\n",
48+
"m"
49+
]
50+
}
51+
],
52+
"metadata": {
53+
"_draft": {
54+
"nbviewer_url": "https://gist.github.com/e7f6b078c47babcbc944e4486267d415"
55+
},
56+
"gist": {
57+
"data": {
58+
"description": "Untitled.ipynb",
59+
"public": true
60+
},
61+
"id": "e7f6b078c47babcbc944e4486267d415"
62+
},
63+
"kernelspec": {
64+
"display_name": "Python [default]",
65+
"language": "python",
66+
"name": "python3"
67+
},
68+
"language_info": {
69+
"codemirror_mode": {
70+
"name": "ipython",
71+
"version": 3
72+
},
73+
"file_extension": ".py",
74+
"mimetype": "text/x-python",
75+
"name": "python",
76+
"nbconvert_exporter": "python",
77+
"pygments_lexer": "ipython3",
78+
"version": "3.6.2"
79+
}
80+
},
81+
"nbformat": 4,
82+
"nbformat_minor": 2
83+
}

folium/plugins/__init__.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,25 @@
1313
from .heat_map import HeatMap
1414
from .image_overlay import ImageOverlay
1515
from .marker_cluster import MarkerCluster
16+
from .measure_control import MeasureControl
1617
from .polyline_text_path import PolyLineTextPath
1718
from .scroll_zoom_toggler import ScrollZoomToggler
1819
from .terminator import Terminator
1920
from .timestamped_geo_json import TimestampedGeoJson
2021
from .timestamped_wmstilelayer import TimestampedWmsTileLayers
2122

2223
__all__ = [
23-
'MarkerCluster',
24-
'FastMarkerCluster',
25-
'ScrollZoomToggler',
26-
'Terminator',
2724
'BoatMarker',
28-
'TimestampedGeoJson',
25+
'FastMarkerCluster',
26+
'FloatImage',
27+
'Fullscreen',
2928
'HeatMap',
3029
'ImageOverlay',
31-
'Fullscreen',
30+
'MarkerCluster',
31+
'MeasureControl',
3232
'PolyLineTextPath',
33-
'FloatImage',
33+
'ScrollZoomToggler',
34+
'Terminator',
35+
'TimestampedGeoJson',
3436
'TimestampedWmsTileLayers'
3537
]

folium/plugins/measure_control.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""
2+
Measure plugin
3+
--------------
4+
5+
Coordinate, linear, and area measure control for folium maps.
6+
"""
7+
8+
import json
9+
10+
from branca.element import MacroElement, Figure, JavascriptLink, CssLink
11+
12+
from jinja2 import Template
13+
14+
15+
class MeasureControl(MacroElement):
16+
"""Adds a measurem widget on the map.
17+
Parameters
18+
----------
19+
position: location of the widget
20+
default is 'topright'.
21+
22+
primary_length_unit and secondary_length_unit: length units
23+
defaults are 'meters' and 'miles' respectively.
24+
25+
primary_area_unit and secondary_area_unit: ara units
26+
defaults are 'sqmeters' and 'acres' respectively.
27+
28+
For more information see https://github.com/ljagis/leaflet-measure
29+
"""
30+
31+
def __init__(self, position='topright', primary_length_unit='meters',
32+
secondary_length_unit='miles', primary_area_unit='sqmeters',
33+
secondary_area_unit='acres'):
34+
"""Coordinate, linear, and area measure control"""
35+
super(MeasureControl, self).__init__()
36+
self._name = 'MeasureControl'
37+
38+
options = {
39+
'position': position,
40+
'primaryLengthUnit': primary_length_unit,
41+
'secondaryLengthUnit': secondary_length_unit,
42+
'primaryAreaUnit': primary_area_unit,
43+
'secondaryAreaUnit': secondary_area_unit,
44+
}
45+
self.options = json.dumps(options)
46+
47+
self._template = Template("""
48+
{% macro script(this, kwargs) %}
49+
var {{this.get_name()}} = new L.Control.Measure(
50+
{{ this.options }});
51+
{{this._parent.get_name()}}.addControl({{this.get_name()}});
52+
53+
{% endmacro %}
54+
""") # noqa
55+
56+
def render(self, **kwargs):
57+
super(MeasureControl, self).render()
58+
59+
figure = self.get_root()
60+
assert isinstance(figure, Figure), ('You cannot render this Element '
61+
'if it is not in a Figure.')
62+
63+
figure.header.add_child(
64+
JavascriptLink('https://cdn.rawgit.com/ljagis/leaflet-measure/2.1.7/dist/leaflet-measure.js')) # noqa
65+
66+
figure.header.add_child(
67+
CssLink('https://cdn.rawgit.com/ljagis/leaflet-measure/2.1.7/dist/leaflet-measure.css')) # noqa

0 commit comments

Comments
 (0)