You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 11:18:16