Folium如何实现标记icon颜色随当前日期动态变化无需修改生成的HTML?
解决方案
核心问题原因
你直接将eval语句传入folium.Icon(color=)参数无效,是因为Folium默认会对所有传入的字符串参数做HTML转义处理,避免注入风险,所以JS逻辑会被转换为纯文本字符串,不会被浏览器识别为可执行代码。
实现方法
方法1:自定义Icon类重写渲染模板(推荐)
直接重写Folium图标的Jinja2渲染模板,把动态颜色判断逻辑内置到模板中,生成的HTML文件直接自带执行逻辑,无需事后修改。
Python实现代码如下:
import folium from folium.plugins import AwesomeMarkers # 自定义支持动态日期判断的图标类 class DynamicDateIcon(AwesomeMarkers): _template = """ {% macro script(this, kwargs) %} var {{ this.get_name() }} = L.AwesomeMarkers.icon({ "extraClasses": "{{ this.extra_classes }}", "icon": "{{ this.icon }}", "iconColor": "{{ this.icon_color }}", "markerColor": eval(` const targetDate = new Date("{{ this.target_date }}").setHours(0,0,0,0); const nowDate = new Date().setHours(0,0,0,0); if (targetDate < nowDate) { "lightgray" } else if (targetDate == nowDate) { "red" } else { "green" } `), "prefix": "{{ this.prefix }}" }); {% endmacro %} """ def __init__(self, target_date, icon="info-sign", icon_color="white", prefix="glyphicon", **kwargs): super().__init__(icon=icon, icon_color=icon_color, prefix=prefix, **kwargs) self.target_date = target_date # 调用示例 m = folium.Map(location=[39.9, 116.4], zoom_start=10) # 每个标记单独传入对应的目标日期即可 folium.Marker( location=[39.9, 116.4], icon=DynamicDateIcon(target_date="2021-09-01") ).add_to(m) m.save("dynamic_icon_map.html")
方法2:全局注入JS逻辑批量修改
如果不想自定义类,也可以在地图生成后插入一段全局JS,页面加载完成后遍历所有标记,根据绑定的目标日期属性修改图标颜色。
Python实现代码如下:
import folium from folium import Element m = folium.Map(location=[39.9, 116.4], zoom_start=10) # 给标记添加自定义属性存储目标日期 marker = folium.Marker( location=[39.9, 116.4], icon=folium.Icon(color="blue") # 此处默认颜色会被JS覆盖,可随意填写 ) marker.options['target_date'] = "2021-09-01" marker.add_to(m) # 插入全局动态颜色修改逻辑 dynamic_js = Element(""" <script> document.addEventListener('DOMContentLoaded', function() { {{ this.parent.get_name() }}.eachLayer(function(layer) { if (layer.options.target_date) { const targetDate = new Date(layer.options.target_date).setHours(0,0,0,0); const nowDate = new Date().setHours(0,0,0,0); let color; if (targetDate < nowDate) color = "lightgray"; else if (targetDate == nowDate) color = "red"; else color = "green"; layer.setIcon(L.AwesomeMarkers.icon({ icon: "info-sign", iconColor: "white", markerColor: color, prefix: "glyphicon" })); } }); }); </script> """) m.get_root().html.add_child(dynamic_js) m.save("dynamic_icon_map.html")
说明
- 两种方法都无需事后通过正则修改生成的HTML代码,直接生成的文件即可正常运行
- 标记数量较多时推荐使用方法1,性能更优,无需页面加载后二次遍历修改标记
内容的提问来源于stack exchange,提问作者Seminko
相关产品推荐
相关产品推荐

