MapLibre GL JS第19课:实时更新要素

📌 学习目标

  • 掌握实时更新要素的实现方法
  • 理解相关API的使用
  • 能够独立完成类似功能开发

🎯 核心概念

通过更新数据实时更改地图上的现有要素。

💻 完 整 代 码

代码示例

js 复制代码
const map = new maplibregl.Map({
    container: 'map',
    style: 'https://tiles.openfreemap.org/styles/bright',
    zoom: 0
});

map.on('load', () => {
    // 这里我们使用D3来获取JSON数据,以便我们可以单独解析和使用它。
    // 你可以使用任何请求方法(库或其他方式)。
    d3.json(
        'https://maplibre.org/maplibre-gl-js/docs/assets/hike.geojson',
        (err, data) => {
            if (err) throw err;

            // 保存完整的坐标列表,用于后续使用
            const coordinates = data.features[0].geometry.coordinates;

            // 仅显示第一个坐标
            data.features[0].geometry.coordinates = [coordinates[0]];

            // 添加要素到地图中
            map.addSource('trace', {type: 'geojson', data});
            map.addLayer({
                'id': 'trace',
                'type': 'line',
                'source': 'trace',
                'paint': {
                    'line-color': 'yellow',
                    'line-opacity': 0.75,
                    'line-width': 5
                }
            });

            // 设置视口
            map.jumpTo({'center': coordinates[0], 'zoom': 14});
            map.setPitch(30);

            // 定时添加更多坐标并更新地图数据
            let i = 0;
            const timer = window.setInterval(() => {
                if (i < coordinates.length) {
                    data.features[0].geometry.coordinates.push(
                        coordinates[i]
                    );
                    map.getSource('trace').setData(data);
                    map.panTo(coordinates[i]);
                    i++;
                } else {
                    window.clearInterval(timer);
                }
            }, 10);
        }
    );
});

代码示例

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Update a feature in realtime</title>
    <meta property="og:description" content="通过更新数据实时更改地图上的现有要素。" />
    <meta property="og:created" content="2025-06-25" />
    <meta charset='utf-8'>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel='stylesheet' href='https://unpkg.com/maplibre-gl@5.24.0/dist/maplibre-gl.css' />
    <script src='https://unpkg.com/maplibre-gl@5.24.0/dist/maplibre-gl.js'></script>
    <style>
        body { margin: 0; padding: 0; }
        html, body, #map { height: 100%; }
    </style>
</head>
<body>
<div id="map"></div>

<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
    const map = new maplibregl.Map({
        container: 'map',
        style: 'https://tiles.openfreemap.org/styles/bright',
        zoom: 0
    });

    map.on('load', () => {
        // 这里使用D3获取JSON数据,以便我们可以独立于GL JS在添加的源中使用它
        // 进行解析和使用。您可以使用任何请求方法(库或其他方式)。
        d3.json(
            'https://maplibre.org/maplibre-gl-js/docs/assets/hike.geojson',
            (err, data) => {
                if (err) throw err;

                // 保存完整的坐标列表供后续使用
                const coordinates = data.features[0].geometry.coordinates;

                // 首先只显示第一个坐标
                data.features[0].geometry.coordinates = [coordinates[0]];

                // 将其添加到地图
                map.addSource('trace', {type: 'geojson', data});
                map.addLayer({
                    'id': 'trace',
                    'type': 'line',
                    'source': 'trace',
                    'paint': {
                        'line-color': 'yellow',
                        'line-opacity': 0.75,
                        'line-width': 5
                    }
                });

                // 设置视口
                map.jumpTo({'center': coordinates[0], 'zoom': 14});
                map.setPitch(30);

                // 定期从保存的列表中添加更多坐标并更新地图
                let i = 0;
                const timer = window.setInterval(() => {
                    if (i < coordinates.length) {
                        data.features[0].geometry.coordinates.push(
                            coordinates[i]
                        );
                        map.getSource('trace').setData(data);
                        map.panTo(coordinates[i]);
                        i++;
                    } else {
                        window.clearInterval(timer);
                    }
                }, 10);
            }
        );
    });
</script>
</body>
</html>

🔍 代码解析

1. 初始化地图

使用 new maplibregl.Map() 创建地图实例,配置基本参数。本示例使用D3.js加载远程GeoJSON数据。

2. 加载GeoJSON数据

使用D3.js的 d3.json() 方法加载远程徒步路线数据,保存完整坐标列表供后续动画使用。

3. 初始化动画

初始时只显示第一个坐标点,然后通过定时器逐步添加更多坐标。

4. 实时更新数据

使用 map.getSource('trace').setData(data) 方法实时更新数据源,实现轨迹动画效果。

5. 地图跟随

使用 map.panTo() 方法使地图跟随轨迹移动。

⚙️ 参数说明

参数 类型 必填 说明
container string 地图容器ID
style string 地图样式URL
zoom number 初始缩放级别,默认0

setData 方法

参数 类型 说明
data object GeoJSON数据对象

🎨 效果说明

运行代码后:

  • 地图初始显示全球视图(zoom: 0)
  • 加载GeoJSON数据后,地图定位到徒步路线起点
  • 黄色轨迹线(#ffff00)逐点绘制,形成动画效果
  • 地图跟随轨迹移动,保持轨迹在视野中心
  • 动画完成后自动停止

💡 常 见 问 题

Q1: 如何优化动画性能?

A: 可以使用 requestAnimationFrame 替代 setInterval,或降低更新频率。

Q2: 如何实现平滑的相机跟随?

A: 使用 map.easeTo() 替代 map.panTo() 实现平滑过渡。

Q3: 不使用D3.js如何加载数据?

A: 可以使用原生 fetch() API:

javascript 复制代码
fetch(url)
    .then(response => response.json())
    .then(data => { /* 处理数据 */ });

📝 练习任务

  1. 基础练习:修改动画速度(setInterval的间隔时间)
  2. 进阶挑战:添加平滑相机跟随效果
  3. 拓展思考:如何实现轨迹颜色渐变?

🌟 最佳实践

  1. 性能优化 : 使用 requestAnimationFrame 确保动画帧率稳定
  2. 数据管理 : 避免频繁创建新数据源,使用 setData 更新
  3. 资源清理: 动画结束后清除定时器,避免内存泄漏
  4. 降级处理: 提供数据加载失败的fallback方案

🔗 延伸阅读


本文是MapLibre GL JS实践课程系列的一部分,欢迎关注收藏

相关推荐
Mr.Daozhi1 小时前
RAG 进阶实战:跑通 Demo 后我连续翻了 6 次车,逐一修复才真正可用(含 Gradio Web 版)
前端·数据库·langchain·大模型·gradio·rag·科研工具
哆来A梦没有口袋2 小时前
干货精讲 | 初级CSS面试高频考题
前端·css·面试
掘金012 小时前
EmbedPDF Vue 版 完整正文文档 全网首发
前端
OpenTiny社区2 小时前
操作ArkTS页面跳转及路由相关心得
前端·typescript·web·opentiny
xiaohua0708day2 小时前
Lodash库
前端·javascript·vue.js
huakoh2 小时前
Claude Code 从零到上手指南:国产工具链复现80% Agent能力,DeepSeek+LangChain实战
前端
Ankkaya2 小时前
浏览器插件接入 Google 登录
前端
Asmewill2 小时前
DeepAgents学习笔记一(构建深度多智能体)
前端
万物皆对象6662 小时前
切换路由时页面空白问题(vue3)
前端·vue.js·typescript