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

Dash Leaflet自定义标记图标:实现类Folium标记效果

需求与问题

我同时使用Folium和Dash Leaflet,希望二者的标记功能实现逻辑保持统一。目前已在Dash Leaflet中实现图片替换标记,但存在以下问题:

  • 标记坐标点对准图片中心,缩放时始终保持中心对齐,需要实现普通标记底座对准坐标点的效果。
  • 想要复刻Folium的标记能力:支持修改标记颜色,且能使用Font-Awesome 4.0、Bootstrap 3及Ionicons 1.5.2提供的图标。

现有Dash Leaflet实现代码:

import dash_leaflet as dl
import dash_leaflet.express as dlx
from dash import html, Dash
from dash_extensions.javascript import assign
import json
locations = '''{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Point",
        "coordinates": [
          -74.00570869445801,
          40.713175131022695
        ]
      }
    }
  ]
}'''
use_icon = assign("""function(feature, latlng){
const i = L.icon({iconUrl: `https://cdn4.iconfinder.com/data/icons/standard-free-icons/139/Checkin01-512.png`, iconSize: [40, 40]});
return L.marker(latlng, {icon: i});
}""")
app = Dash()
app.layout = html.Div(children=[
                        dl.Map(center=[39, -98], zoom=4, children=[
                            dl.TileLayer(),
                            dl.GeoJSON(data=dlx.geojson_to_geobuf(json.loads(locations)), 
                                format='geobuf', 
                                options=dict(pointToLayer=use_icon))],
                            style={'width': '100%', 'height': '100vh'})])

if __name__ == "__main__":
    app.run_server(debug=False)

Folium目标效果示例代码:

import folium
m = folium.Map()
folium.Marker((40.713175131022695, -74.00570869445801), 
              icon=folium.Icon(color='black', icon='fire', prefix='fa')).add_to(m)
m

注:需用这些标记实现数据过滤,不接受通过iframe嵌入Folium地图的方案。


解决方案

1. 修复图标锚点(底座对准坐标)

Leaflet的L.icon支持iconAnchor参数,可指定图标与地图坐标点对齐的位置。对于底座对准需求,只需将锚点设置为图标的底部中心:

function(feature, latlng){
const i = L.icon({
    iconUrl: `https://cdn4.iconfinder.com/data/icons/standard-free-icons/139/Checkin01-512.png`, 
    iconSize: [40, 40],
    iconAnchor: [20, 40]  // x轴取中心,y轴取底部,实现底座对准坐标
});
return L.marker(latlng, {icon: i});
}

2. 实现字体图标与颜色自定义

要复刻Folium的字体图标功能,需加载对应字体库,并使用Leaflet的DivIcon通过CSS渲染图标,完整实现代码如下:

import dash_leaflet as dl
import dash_leaflet.express as dlx
from dash import html, Dash
from dash_extensions.javascript import assign
import json

# 注入字体库资源
app = Dash(__name__)
app.index_string = '''
<!DOCTYPE html>
<html>
    <head>
        {%metas%}
        <title>{%title%}</title>
        {%favicon%}
        {%css%}
        <!-- 加载所需字体库 -->
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.3/css/font-awesome.min.css">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
        <link rel="stylesheet" href="https://code.ionicframework.com/ionicons/1.5.2/css/ionicons.min.css">
        <style>
            /* 自定义图标基础样式 */
            .custom-icon {
                display: flex;
                align-items: center;
                justify-content: center;
                font-size: 24px;
                width: 40px;
                height: 40px;
                border-radius: 50%;
                color: white;
            }
        </style>
    </head>
    <body>
        {%app_entry%}
        <footer>
            {%config%}
            {%scripts%}
            {%renderer%}
        </footer>
    </body>
</html>
'''

# 定义自定义图标生成逻辑,匹配Folium的参数格式
custom_icon_factory = assign("""function(feature, latlng){
    const props = feature.properties || {};
    // 从GeoJSON属性中读取配置,默认值与Folium对齐
    const color = props.color || 'blue';
    const icon = props.icon || 'info-sign';
    const prefix = props.prefix || 'glyphicon';
    
    // 构建字体图标类名
    const iconClass = `${prefix} ${prefix}-${icon}`;
    // 创建DivIcon渲染字体图标
    const divIcon = L.divIcon({
        className: 'custom-icon',
        html: `<i class="${iconClass}"></i>`,
        iconSize: [40, 40],
        iconAnchor: [20, 40],  // 底座对准坐标点
        popupAnchor: [0, -40]  // 调整弹窗位置避免遮挡
    });
    
    // 动态设置图标背景色
    const marker = L.marker(latlng, {icon: divIcon});
    marker._icon.style.backgroundColor = color;
    
    return marker;
}""")

# 带图标配置的GeoJSON数据(properties字段存储颜色、图标、前缀)
locations = '''{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "color": "black",
        "icon": "fire",
        "prefix": "fa"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          -74.00570869445801,
          40.713175131022695
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "color": "red",
        "icon": "home",
        "prefix": "glyphicon"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          -122.4194,
          37.7749
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "color": "green",
        "icon": "map-marker",
        "prefix": "ion"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          -95.3698,
          29.7604
        ]
      }
    }
  ]
}'''

app.layout = html.Div(children=[
    dl.Map(center=[39, -98], zoom=4, children=[
        dl.TileLayer(),
        dl.GeoJSON(
            data=dlx.geojson_to_geobuf(json.loads(locations)), 
            format='geobuf', 
            options=dict(pointToLayer=custom_icon_factory)
        )
    ], style={'width': '100%', 'height': '100vh'})
])

if __name__ == "__main__":
    app.run_server(debug=False)

代码说明:

  • 字体库加载:通过index_string注入三个字体库资源,确保图标正常渲染。
  • 参数对齐:通过GeoJSON的properties字段传递color/icon/prefix参数,和Folium的Icon配置逻辑完全一致。
  • 锚点设置:iconAnchor固定为底部中心,实现和普通标记一致的坐标对齐效果。
  • 数据过滤支持:基于Dash Leaflet原生组件,可直接通过回调监听标记交互事件,结合Dash状态管理实现数据过滤功能。

内容的提问来源于stack exchange,提问作者Robert Allan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:45:44