Skip to content

Commit c50ab41

Browse files
authored
Cleanup MacroElements (#2088)
* Cleanup macroelements Earlier I noted many macroelements do not fully use the facilities of Figure, but instead in render manipulate the parent Figure. Step 1: remove GlobalSwitches as Element * Based on review comments
1 parent 74b23d4 commit c50ab41

File tree

6 files changed

+151
-198
lines changed

6 files changed

+151
-198
lines changed

folium/elements.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ class JSCSSMixin(MacroElement):
1818
default_js: List[Tuple[str, str]] = []
1919
default_css: List[Tuple[str, str]] = []
2020

21+
# Since this is typically used as a mixin, we cannot
22+
# override the _template member variable here. It would
23+
# be overwritten by any subclassing class that also has
24+
# a _template variable.
2125
def render(self, **kwargs):
2226
figure = self.get_root()
2327
assert isinstance(

folium/folium.py

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,29 @@ class Map(JSCSSMixin, Evented):
192192
}
193193
.leaflet-container { font-size: {{this.font_size}}; }
194194
</style>
195+
196+
<style>html, body {
197+
width: 100%;
198+
height: 100%;
199+
margin: 0;
200+
padding: 0;
201+
}
202+
</style>
203+
204+
<style>#map {
205+
position:absolute;
206+
top:0;
207+
bottom:0;
208+
right:0;
209+
left:0;
210+
}
211+
</style>
212+
213+
<script>
214+
L_NO_TOUCH = {{ this.global_switches.no_touch |tojson}};
215+
L_DISABLE_3D = {{ this.global_switches.disable_3d|tojson }};
216+
</script>
217+
195218
{% endmacro %}
196219
197220
{% macro html(this, kwargs) %}
@@ -304,6 +327,8 @@ def __init__(
304327
else:
305328
self.zoom_control_position = False
306329

330+
self.global_switches = GlobalSwitches(no_touch, disable_3d)
331+
307332
self.options = remove_empty(
308333
max_bounds=max_bounds_array,
309334
zoom=zoom_start,
@@ -312,8 +337,6 @@ def __init__(
312337
**kwargs,
313338
)
314339

315-
self.global_switches = GlobalSwitches(no_touch, disable_3d)
316-
317340
self.objects_to_stay_in_front: List[Layer] = []
318341

319342
if isinstance(tiles, TileLayer):
@@ -377,45 +400,6 @@ def _repr_png_(self) -> Optional[bytes]:
377400
return None
378401
return self._to_png()
379402

380-
def render(self, **kwargs):
381-
"""Renders the HTML representation of the element."""
382-
figure = self.get_root()
383-
assert isinstance(
384-
figure, Figure
385-
), "You cannot render this Element if it is not in a Figure."
386-
387-
# Set global switches
388-
figure.header.add_child(self.global_switches, name="global_switches")
389-
390-
figure.header.add_child(
391-
Element(
392-
"<style>html, body {"
393-
"width: 100%;"
394-
"height: 100%;"
395-
"margin: 0;"
396-
"padding: 0;"
397-
"}"
398-
"</style>"
399-
),
400-
name="css_style",
401-
)
402-
403-
figure.header.add_child(
404-
Element(
405-
"<style>#map {"
406-
"position:absolute;"
407-
"top:0;"
408-
"bottom:0;"
409-
"right:0;"
410-
"left:0;"
411-
"}"
412-
"</style>"
413-
),
414-
name="map_style",
415-
)
416-
417-
super().render(**kwargs)
418-
419403
def show_in_browser(self) -> None:
420404
"""Display the Map in the default web browser."""
421405
with temp_html_filepath(self.get_root().render()) as fname:

folium/plugins/draw.py

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from branca.element import Element, Figure, MacroElement
1+
from branca.element import MacroElement
22

33
from folium.elements import JSCSSMixin
44
from folium.template import Template
@@ -60,6 +60,29 @@ class Draw(JSCSSMixin, MacroElement):
6060

6161
_template = Template(
6262
"""
63+
{% macro html(this, kwargs) %}
64+
{% if this.export %}
65+
<style>
66+
#export {
67+
position: absolute;
68+
top: 5px;
69+
right: 10px;
70+
z-index: 999;
71+
background: white;
72+
color: black;
73+
padding: 6px;
74+
border-radius: 4px;
75+
font-family: 'Helvetica Neue';
76+
cursor: pointer;
77+
font-size: 12px;
78+
text-decoration: none;
79+
top: 90px;
80+
}
81+
</style>
82+
<a href='#' id='export'>Export</a>
83+
{% endif %}
84+
{% endmacro %}
85+
6386
{% macro script(this, kwargs) %}
6487
var options = {
6588
position: {{ this.position|tojson }},
@@ -155,35 +178,3 @@ def __init__(
155178
self.draw_options = draw_options or {}
156179
self.edit_options = edit_options or {}
157180
self.on = on or {}
158-
159-
def render(self, **kwargs):
160-
super().render(**kwargs)
161-
162-
figure = self.get_root()
163-
assert isinstance(
164-
figure, Figure
165-
), "You cannot render this Element if it is not in a Figure."
166-
167-
export_style = """
168-
<style>
169-
#export {
170-
position: absolute;
171-
top: 5px;
172-
right: 10px;
173-
z-index: 999;
174-
background: white;
175-
color: black;
176-
padding: 6px;
177-
border-radius: 4px;
178-
font-family: 'Helvetica Neue';
179-
cursor: pointer;
180-
font-size: 12px;
181-
text-decoration: none;
182-
top: 90px;
183-
}
184-
</style>
185-
"""
186-
export_button = """<a href='#' id='export'>Export</a>"""
187-
if self.export:
188-
figure.header.add_child(Element(export_style), name="export")
189-
figure.html.add_child(Element(export_button), name="export_button")

folium/plugins/heat_map_withtime.py

Lines changed: 81 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from branca.element import Element, Figure
2-
31
from folium.elements import JSCSSMixin
42
from folium.map import Layer
53
from folium.template import Template
@@ -61,6 +59,87 @@ class HeatMapWithTime(JSCSSMixin, Layer):
6159

6260
_template = Template(
6361
"""
62+
{% macro header(this, kwargs) %}
63+
<script>
64+
var TDHeatmap = L.TimeDimension.Layer.extend({
65+
initialize: function(data, options) {
66+
var heatmapCfg = {
67+
radius: 15,
68+
blur: 0.8,
69+
maxOpacity: 1.,
70+
scaleRadius: false,
71+
useLocalExtrema: false,
72+
latField: 'lat',
73+
lngField: 'lng',
74+
valueField: 'count',
75+
defaultWeight : 1,
76+
};
77+
heatmapCfg = $.extend({}, heatmapCfg, options.heatmapOptions || {});
78+
var layer = new HeatmapOverlay(heatmapCfg);
79+
L.TimeDimension.Layer.prototype.initialize.call(this, layer, options);
80+
this._currentLoadedTime = 0;
81+
this._currentTimeData = {
82+
data: []
83+
};
84+
this.data= data;
85+
this.defaultWeight = heatmapCfg.defaultWeight || 1;
86+
},
87+
onAdd: function(map) {
88+
L.TimeDimension.Layer.prototype.onAdd.call(this, map);
89+
map.addLayer(this._baseLayer);
90+
if (this._timeDimension) {
91+
this._getDataForTime(this._timeDimension.getCurrentTime());
92+
}
93+
},
94+
_onNewTimeLoading: function(ev) {
95+
this._getDataForTime(ev.time);
96+
return;
97+
},
98+
isReady: function(time) {
99+
return (this._currentLoadedTime == time);
100+
},
101+
_update: function() {
102+
this._baseLayer.setData(this._currentTimeData);
103+
return true;
104+
},
105+
_getDataForTime: function(time) {
106+
delete this._currentTimeData.data;
107+
this._currentTimeData.data = [];
108+
var data = this.data[time-1];
109+
for (var i = 0; i < data.length; i++) {
110+
this._currentTimeData.data.push({
111+
lat: data[i][0],
112+
lng: data[i][1],
113+
count: data[i].length>2 ? data[i][2] : this.defaultWeight
114+
});
115+
}
116+
this._currentLoadedTime = time;
117+
if (this._timeDimension && time == this._timeDimension.getCurrentTime() && !this._timeDimension.isLoading()) {
118+
this._update();
119+
}
120+
this.fire('timeload', {
121+
time: time
122+
});
123+
}
124+
});
125+
126+
L.Control.TimeDimensionCustom = L.Control.TimeDimension.extend({
127+
initialize: function(index, options) {
128+
var playerOptions = {
129+
buffer: 1,
130+
minBufferReady: -1
131+
};
132+
options.playerOptions = $.extend({}, playerOptions, options.playerOptions || {});
133+
L.Control.TimeDimension.prototype.initialize.call(this, options);
134+
this.index = index;
135+
},
136+
_getDisplayDateFormat: function(date) {
137+
return this.index[date.getTime()-1];
138+
}
139+
});
140+
</script>
141+
{% endmacro %}
142+
64143
{% macro script(this, kwargs) %}
65144
66145
var times = {{this.times}};
@@ -202,101 +281,6 @@ def __init__(
202281
self.time_slider_drag_update = "false"
203282
self.style_NS = "leaflet-control-timecontrol"
204283

205-
def render(self, **kwargs):
206-
super().render(**kwargs)
207-
208-
figure = self.get_root()
209-
assert isinstance(
210-
figure, Figure
211-
), "You cannot render this Element if it is not in a Figure."
212-
213-
figure.header.add_child(
214-
Element(
215-
"""
216-
<script>
217-
var TDHeatmap = L.TimeDimension.Layer.extend({
218-
219-
initialize: function(data, options) {
220-
var heatmapCfg = {
221-
radius: 15,
222-
blur: 0.8,
223-
maxOpacity: 1.,
224-
scaleRadius: false,
225-
useLocalExtrema: false,
226-
latField: 'lat',
227-
lngField: 'lng',
228-
valueField: 'count',
229-
defaultWeight : 1,
230-
};
231-
heatmapCfg = $.extend({}, heatmapCfg, options.heatmapOptions || {});
232-
var layer = new HeatmapOverlay(heatmapCfg);
233-
L.TimeDimension.Layer.prototype.initialize.call(this, layer, options);
234-
this._currentLoadedTime = 0;
235-
this._currentTimeData = {
236-
data: []
237-
};
238-
this.data= data;
239-
this.defaultWeight = heatmapCfg.defaultWeight || 1;
240-
},
241-
onAdd: function(map) {
242-
L.TimeDimension.Layer.prototype.onAdd.call(this, map);
243-
map.addLayer(this._baseLayer);
244-
if (this._timeDimension) {
245-
this._getDataForTime(this._timeDimension.getCurrentTime());
246-
}
247-
},
248-
_onNewTimeLoading: function(ev) {
249-
this._getDataForTime(ev.time);
250-
return;
251-
},
252-
isReady: function(time) {
253-
return (this._currentLoadedTime == time);
254-
},
255-
_update: function() {
256-
this._baseLayer.setData(this._currentTimeData);
257-
return true;
258-
},
259-
_getDataForTime: function(time) {
260-
delete this._currentTimeData.data;
261-
this._currentTimeData.data = [];
262-
var data = this.data[time-1];
263-
for (var i = 0; i < data.length; i++) {
264-
this._currentTimeData.data.push({
265-
lat: data[i][0],
266-
lng: data[i][1],
267-
count: data[i].length>2 ? data[i][2] : this.defaultWeight
268-
});
269-
}
270-
this._currentLoadedTime = time;
271-
if (this._timeDimension && time == this._timeDimension.getCurrentTime() && !this._timeDimension.isLoading()) {
272-
this._update();
273-
}
274-
this.fire('timeload', {
275-
time: time
276-
});
277-
}
278-
});
279-
280-
L.Control.TimeDimensionCustom = L.Control.TimeDimension.extend({
281-
initialize: function(index, options) {
282-
var playerOptions = {
283-
buffer: 1,
284-
minBufferReady: -1
285-
};
286-
options.playerOptions = $.extend({}, playerOptions, options.playerOptions || {});
287-
L.Control.TimeDimension.prototype.initialize.call(this, options);
288-
this.index = index;
289-
},
290-
_getDisplayDateFormat: function(date){
291-
return this.index[date.getTime()-1];
292-
}
293-
});
294-
</script>
295-
""", # noqa
296-
template_name="timeControlScript",
297-
)
298-
)
299-
300284
def _get_self_bounds(self):
301285
"""
302286
Computes the bounds of the object itself (not including it's children)

folium/plugins/search.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from branca.element import MacroElement
22

3-
from folium import Map
43
from folium.elements import JSCSSMixin
54
from folium.features import FeatureGroup, GeoJson, TopoJson
5+
from folium.folium import Map
66
from folium.plugins import MarkerCluster
77
from folium.template import Template
88
from folium.utilities import remove_empty

0 commit comments

Comments
 (0)