Django+Folium实现点击地图标记侧边表格同步显示弹窗信息
实现方案
onclick事件绑定的方案完全可行,不需要大幅改动现有后端逻辑,分三步即可实现点击标记时侧边表格同步展示对应点位信息:
1. 后端调整:输出结构化点位数据,给Marker绑定唯一标识
不要直接把Pandas DataFrame传给模板循环渲染全量数据,提前把点位信息转成前端可直接解析的JSON格式,同时给每个地图标记绑定唯一ID,方便前端做数据匹配。
修改视图代码如下:
import json from django.core.serializers.json import DjangoJSONEncoder locations = Location.objects.values() loc_data = pd.DataFrame(locations) location_map = {} for index, location_info in loc_data.iterrows(): # 给每个点位生成唯一ID loc_id = f"loc_{index}" # 存储点位结构化信息 location_map[loc_id] = { "hostname": location_info["hostname"], "structurename": location_info["structurename"], "domain": location_info["domain"], "ip": location_info["ip"], "personas": location_info["personas"], "cube": location_info["cube"], "cubeurl": location_info["cubeurl"] } # 原有弹窗生成逻辑保持不变 html=f""" <h1>{location_info['hostname']}</h1> <p>Node Attributes: <ul> <li>Structure Name: {location_info["structurename"]}</li> <li>Domain: {location_info["domain"]}</li> <li>IP Address: {location_info["ip"]}</li> <li>Persona: {location_info["personas"]}</li> </ul> {location_info["cube"]} </p> <a href={location_info["cubeurl"]} target = "_blank">Login to cube</a> """ iframe = folium.IFrame(html=html, width=350, height=270) popup = folium.Popup(iframe, max_width=2650) # 按原有规则生成Marker if location_info["cube"] == "Industrial Cube North": marker = folium.Marker( [location_info["latitude"], location_info["longitude"]], popup=popup, icon=folium.Icon(color='darkred'), tooltip=location_info["hostname"] ) elif location_info["cube"] == "Industrial Cube South": marker = folium.Marker( [location_info["latitude"], location_info["longitude"]], popup=popup, icon=folium.Icon(color='green'), tooltip=location_info["hostname"] ) # 给Marker注入自定义属性,绑定唯一ID,方便前端识别 marker.add_child(folium.Element(f'<div class="location-marker" data-loc-id="{loc_id}"></div>')) marker.add_to(m) m = m._repr_html_() context = { "map": m, "location_json": json.dumps(location_map, cls=DjangoJSONEncoder) } return render(request, 'maps/map.html', context)
2. 模板调整:预留固定信息表格位
在模板中地图侧边区域放置固定结构的空表格,默认隐藏,无需循环渲染全量数据:
<div class="content-wrapper"> <div class="map-area"> {{ map|safe }} </div> <div class="table-area"> <p id="select-tip">点击地图标记查看对应服务器详情</p> <table id="server-info-table" style="display: none;"> <thead> <tr> <th>属性项</th> <th>属性值</th> </tr> </thead> <tbody> <tr> <td>主机名</td> <td id="val-hostname"></td> </tr> <tr> <td>结构名称</td> <td id="val-structurename"></td> </tr> <tr> <td>域名</td> <td id="val-domain"></td> </tr> <tr> <td>IP地址</td> <td id="val-ip"></td> </tr> <tr> <td>节点角色</td> <td id="val-personas"></td> </tr> <tr> <td>所属Cube</td> <td id="val-cube"></td> </tr> <tr> <td>管理入口</td> <td><a id="val-cubeurl" target="_blank">登录Cube</a></td> </tr> </tbody> </table> </div> </div>
3. 前端逻辑:绑定标记点击事件,动态填充表格
在模板底部添加JavaScript代码,监听地图标记的点击事件,匹配对应点位数据填充表格:
// 解析后端传入的点位数据 const serverData = JSON.parse('{{ location_json|escapejs }}'); window.addEventListener('load', () => { const markers = document.querySelectorAll('.location-marker'); const tipEl = document.getElementById('select-tip'); const tableEl = document.getElementById('server-info-table'); markers.forEach(markerTag => { // 定位到可点击的Marker元素 const clickableMarker = markerTag.closest('.leaflet-marker-icon'); if (!clickableMarker) return; clickableMarker.addEventListener('click', () => { const locId = markerTag.dataset.locId; const currentServer = serverData[locId]; if (!currentServer) return; // 填充表格内容 document.getElementById('val-hostname').textContent = currentServer.hostname; document.getElementById('val-structurename').textContent = currentServer.structurename; document.getElementById('val-domain').textContent = currentServer.domain; document.getElementById('val-ip').textContent = currentServer.ip; document.getElementById('val-personas').textContent = currentServer.personas; document.getElementById('val-cube').textContent = currentServer.cube; document.getElementById('val-cubeurl').href = currentServer.cubeurl; // 切换显示状态 tipEl.style.display = 'none'; tableEl.style.display = 'block'; }) }) })
若使用高版本Folium时无法触发点击事件,可打开浏览器开发者工具点选标记元素,确认Marker对应的DOM类名,替换代码中
.leaflet-marker-icon选择器即可,核心逻辑无需调整。
之前直接传递popup、iframe对象失败,是因为两者都是Python端的Folium实例对象,无法被前端直接解析,将业务数据序列化为标准JSON传递是兼容性最高的方案,不会出现序列化报错。
内容的提问来源于stack exchange,提问作者Conor Lacey
相关产品推荐
相关产品推荐

