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

如何基于TimestampedGeoJson实现带航向的船只路径动画?

实现带航向的船只路径航行动画

问题背景

已通过TimestampedGeoJson实现船只沿路径航行的基础动画:路径显示为绿色线条,船只标记为圆形。但圆形标记无法体现船只航向,需在保留原有路径显示、时间滑块、动画控制等功能的前提下,替换为带航向的船只标记。

基础实现代码如下:

# circle with following line
features = [
    {
        'type': 'Feature',
        'geometry': {
            'type': 'LineString',
            'coordinates': coordinates_list,
        }, 
        'properties': {
            'popup': 'ship position',
            'times': times_list,
            'icon': 'circle',
            'iconstyle': {
                'fillColor': 'green',
                'fillOpacity': 0.6,
                'stroke': 'false',
                'radius': 13,
            },
            'style': {
                'color': 'green',
                'weight': 2,
                'opacity': 0.6
            },
            'id': 'man',
        },
    }
]

plugins.TimestampedGeoJson(
    {'type': 'FeatureCollection', 'features': features},
    period='PT30M',
    add_last_point=True,
    auto_play=False,
    loop=False,
    max_speed=1,
    loop_button=True,
    date_options='YYYY/MM/DD',
    time_slider_drag_update=True,
    duration='P1M',
).add_to(m)

解决方案

核心思路是:拆分路径与标记为两个独立Feature,计算每个路径点的航向角度,使用自定义可旋转图标作为船只标记。

步骤1:计算航向角度

通过两点坐标计算船只的航行方位角(航向),保证每个路径点对应正确的航向:

import math

def calculate_bearing(lat1, lon1, lat2, lon2):
    # 计算两点间的方位角,返回0-360度的航向值
    lon1, lat1, lon2, lat2 = map(math.radians, [lon1, lat1, lon2, lat2])
    dlon = lon2 - lon1
    x = math.cos(lat2) * math.sin(dlon)
    y = math.cos(lat1) * math.sin(lat2) - math.sin(lat1) * math.cos(lat2) * math.cos(dlon)
    bearing = math.degrees(math.atan2(x, y))
    return (bearing + 360) % 360

# 为每个路径点计算航向(最后一个点复用前一个点的航向)
bearings = []
for i in range(len(coordinates_list)):
    if i < len(coordinates_list) - 1:
        lon1, lat1 = coordinates_list[i]
        lon2, lat2 = coordinates_list[i+1]
        bearings.append(calculate_bearing(lat1, lon1, lat2, lon2))
    else:
        bearings.append(bearings[-1] if bearings else 0)

步骤2:重构Feature集合

将原有的单个Feature拆分为静态路径线条和动态船只标记两个Feature,为船只标记配置带旋转的自定义图标:

# 静态路径线条Feature(无时间动画,仅显示路径)
line_feature = {
    'type': 'Feature',
    'geometry': {
        'type': 'LineString',
        'coordinates': coordinates_list,
    },
    'properties': {
        'style': {
            'color': 'green',
            'weight': 2,
            'opacity': 0.6
        }
    }
}

# 动态船只标记Feature(每个点对应时间与航向)
ship_feature = {
    'type': 'Feature',
    'geometry': {
        'type': 'MultiPoint',
        'coordinates': coordinates_list,
    },
    'properties': {
        'popup': 'ship position',
        'times': times_list,
        'icon': 'div-icon',
        # 用SVG绘制三角形作为船只图标,每个点对应不同的旋转角度(航向)
        'iconstyle': [
            {
                'html': f'<svg width="20" height="20" viewBox="0 0 20 20"><polygon points="10,2 18,18 2,18" fill="#2e8b57" opacity="0.8"/></svg>',
                'iconSize': [20, 20],
                'iconAnchor': [10, 10],  # 以图标中心为旋转点
                'rotation': bearing
            } for bearing in bearings
        ],
        'id': 'ship'
    }
}

# 合并两个Feature
features = [line_feature, ship_feature]

# 初始化TimestampedGeoJson,保留原有动画控制参数
plugins.TimestampedGeoJson(
    {'type': 'FeatureCollection', 'features': features},
    period='PT30M',
    add_last_point=True,
    auto_play=False,
    loop=False,
    max_speed=1,
    loop_button=True,
    date_options='YYYY/MM/DD',
    time_slider_drag_update=True,
    duration='P1M',
).add_to(m)

可选优化:使用自定义PNG图标

如果有现成的船只PNG图标,可替换SVG部分,只需修改iconstyle的配置:

'iconstyle': [
    {
        'iconUrl': 'ship-icon.png',  # 替换为你的图标路径
        'iconSize': [30, 30],
        'iconAnchor': [15, 15],  # 确保旋转点为图标中心
        'rotation': bearing
    } for bearing in bearings
]

关键说明

  • 拆分Feature后,路径线条保持静态显示,船只标记随时间滑块动态移动并根据航向旋转
  • iconAnchor必须设置为图标中心,否则旋转方向会出现偏移
  • 若使用PNG图标,需确保图标默认船头朝上,这样旋转角度才能正确对应航行方向

内容的提问来源于stack exchange,提问作者Frank Tap

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 10:10:55