Flask中如何获取Folium标记ID并调用Python函数实现弹窗绘图
问题分析与解决方案
核心问题梳理
你的代码存在以下几个关键问题导致功能失效:
- Marker的ID未绑定到可读取的位置:Folium的
Marker参数id不会自动映射到DOM元素的可读取属性,JS无法提取目标ID - JS执行时机错误:DOM未完全渲染(包括Marker加载完成)就执行元素查询,找不到标记节点
- Python语法错误:使用了JS风格的
//注释,Python需用#;模板字符串的引号转义冗余 - 仅处理单个站点:
if ia==0导致只有第一个气象站被添加标记
修正后的完整代码
import folium, branca, requests from branca.element import Element from flask import Flask, request, jsonify from folium.plugins import LocateControl app = Flask(__name__) @app.route('/') def map(): start_coords = (38.7088, -9.1576) folium_map = folium.Map( location=start_coords, zoom_start=8, max_bounds=True, height="100%", zoom_control=False ) fig = branca.element.Figure(height="100%", width='100%') fig.add_child(folium_map) # 添加地图插件 folium.plugins.Fullscreen(position='bottomleft').add_to(folium_map) folium.LatLngPopup2().add_to(folium_map) LocateControl(strings={'drawMarker':'False'}).add_to(folium_map) ft_grp = folium.map.FeatureGroup(name='Meteo Stations - last 24H', show=False) rsp = requests.get('https://api.ipma.pt/open-data/observation/meteorology/stations/stations.json') codes = rsp.json() # 调整JS模板:使用Leaflet原生事件监听,避免DOM查询漏洞 template = ''' document.addEventListener('DOMContentLoaded', function() { // 获取Leaflet地图实例 var map = window.L.mapInstances[0]; // 监听地图上的标记点击事件 map.on('click', function(e) { if (e.target instanceof L.Marker) { var markerId = e.target.options.markerId; if (markerId) { handleMarkerClick(markerId); } } }); }); function handleMarkerClick(markerId) { $.ajax({ type: "POST", url: "/plot_station", data: JSON.stringify({ id: markerId }), contentType: "application/json; charset=utf-8", dataType: "json", success: function(response) { console.log('请求成功:', response.message); // 后续可在此处添加弹窗展示图表的逻辑 }, error: function(xhr, status, error) { console.error('请求失败:', error); } }); } ''' # 循环处理所有气象站标记 for cd in codes: station_id = cd['properties']['idEstacao'] coord = cd['geometry']['coordinates'] # 创建Marker时将ID存入Leaflet配置,同时设置popup marker = folium.Marker( location=[coord[1], coord[0]], popup=folium.Popup(f"站点ID: {station_id}", max_width=150), options={'markerId': station_id} ).add_to(ft_grp) # 注入自定义JS到地图页面 e = Element(template) html = folium_map.get_root() html.script._children[e.get_name()] = e folium_map.add_child(ft_grp) folium.LayerControl().add_to(folium_map) return fig._repr_html_() @app.route('/plot_station', methods=['POST']) def plot_station(): data = request.get_json() marker_id = data.get('id') print(f"收到站点ID: {marker_id}") if marker_id: # 生成文件示例(后续可替换为图表生成逻辑) filename = f"{marker_id}.txt" with open(filename, 'w') as fid: fid.write(f"站点 {marker_id} 被点击!") return jsonify({"message": f"已处理站点 {marker_id}"}) if __name__ == '__main__': app.run(debug=True)
关键修改说明
Marker ID存储优化:
通过options={'markerId': station_id}将站点ID直接存入Leaflet Marker的配置对象中,无需依赖DOM属性,避免DOM结构变化导致的读取失败。JS事件监听优化:
- 使用
DOMContentLoaded确保地图完全加载后再绑定事件 - 直接监听Leaflet地图的
click事件,通过判断点击目标类型获取Marker,避免DOM查询的兼容性问题
- 使用
修复语法与逻辑问题:
- 替换Python中的
//注释为合法的#注释 - 移除
if ia==0判断,循环所有气象站生成标记 - 简化JS模板的引号使用,删除不必要的转义字符
- 替换Python中的
后续扩展建议:
- 若要在弹窗展示图表,可在
handleMarkerClick的success回调中,将后端生成的图表(如Matplotlib转成的base64图片)插入到自定义弹窗中 - 可结合Bootstrap模态框实现更美观、功能更完善的弹窗效果
- 若要在弹窗展示图表,可在
内容的提问来源于stack exchange,提问作者Elcook
相关产品推荐
相关产品推荐

