☰
使用 Leaflet.js 绘制交互式地图并在页面上标记国际空间站(ISS)实时位置
2026/10/13 2:46:44 网站建设 项目流程
  • 教程
  • 文档
  • 示例工程

【免费下载链接】website-archive

Archive of the Coding Train website (first version)

项目地址:https://gitcode.com/gh_mirrors/we/website-archive
点击查看免费下载

导读

本篇文章对应《Working with Data & APIs in JavaScript》课程第 1.5 讲的核心实战:在纯前端页面中引入 Leaflet.js,搭建一张可缩放、可拖拽的交互式地图,并把从 API 获取到的国际空间站(ISS)实时经纬度坐标绘制为地图标记。读完本文,你将掌握 Leaflet.js 的地图初始化、瓦片图层配置、标记(Marker)管理,以及如何与前一讲学到的fetch()+ JSON 数据加载技术衔接,为后续“定时刷新数据”(setInterval)与“数据库地理数据可视化”打好基础。

一、课程上下文:为什么需要 Leaflet.js

《Working with Data & APIs》是 Coding Train 网站归档的一套 JavaScript 数据与 API 实战课程,其第一组项目为“纯客户端(client-side only)”,目标是用fetch()加载数据并呈现在网页上。课程目录中与本讲直接相关的前置与后续节点包括:

  • 1.1 Fetch:webfetch()API、异步 Promise(async/await);
  • 1.4 JSON:用fetch()加载 JSON 数据并更新 DOM 元素;
  • 1.5 本讲:Leaflet.js 地图:把经纬度坐标渲染成交互式地图;
  • 1.6 用 setInterval() 刷新数据.md):每秒从 ISS API 拉取新数据并更新 DOM。

本讲的定位非常清晰:前面几讲解决了“把数据拿到手”,这一讲解决“把经纬度数据放到地图上”。课程采用的数据源是 Where the ISS at? 提供的 ISS 实时位置接口,该接口同样出现在 1.4-json 讲中,作为 JSON 数据加载的示例来源。也就是说,1.5 讲是对 1.4 讲 JSON 数据的直接可视化落地。

二、Leaflet.js 基础:引入与初始化

Leaflet.js 是一个轻量级、开源、移动端友好的 JavaScript 交互式地图库。与需要 API Key 的商用地图服务不同,Leaflet 本身只负责“渲染地图容器 + 叠加图层”,底图瓦片(tile)通常使用 OpenStreetMap 等免费瓦片服务,非常适合课程与教学场景。

2.1 通过 CDN 引入

在 HTML 中同时引入 Leaflet 的 CSS 与 JS 文件:

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" /> <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"></script>

在仓库的实战示例中可以看到类似的 CDN 引入模式: CC_109_subscriber_map/P5/index.html 通过 CDN 引入 p5.js 与 mappa-mundi 库,再由sketch.js用new Mappa('Leaflet')在 p5 与 Leaflet 之间建立桥梁。这印证了 Leaflet 生态“以 CDN 单文件引入、按需组合其他库”的典型用法。

2.2 创建地图容器与初始化

页面中需要有一个拥有明确高度的 DOM 容器:

<div id="mapid" style="width: 600px; height: 400px;"></div>

随后初始化地图并设置初始视野:

const mymap = L.map('mapid').setView([0, 0], 2);
  • L.map('mapid'):mapid是容器元素的 id;
  • .setView([lat, lng], zoom):第一个参数是初始中心点[纬度, 经度],第二个参数是缩放级别(zoom)。这里把中心放在[0, 0]、缩放级别为 2,即可获得一张可看到全球的初始视图,方便后续标记移动的 ISS。

2.3 添加瓦片图层

地图容器创建后,还需要指定底图。使用 OpenStreetMap 的标准瓦片并注明版权归属:

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(mymap);

参数说明:

参数含义
{s}子域名占位符,Leaflet 会按a/b/c轮询以加速瓦片加载
{z}缩放级别
{x}/{y}瓦片行列坐标
attribution版权署名,随地图渲染在角落,用于满足 OSM 的使用条款

仓库中 CC_109_subscriber_map/P5/sketch.js 的瓦片配置使用了类似的 URL 模板:

const options = { lat: 0, lng: 0, zoom: 1.5, style: 'http://{s}.tile.osm.org/{z}/{x}/{y}.png' };

可以看到同一套{s}/{z}/{x}/{y}瓦片寻址规范也被 Mappa(Leaflet 的封装)沿用,这说明了该 URL 模板是 OpenStreetMap 系瓦片服务的通用约定。

三、数据来源:ISS 实时位置 JSON API

本讲的核心数据来自 Where the ISS at? 提供的开放接口,接口返回 JSON,典型结构大致为:

{ "timestamp": 1558976996, "iss_position": { "latitude": "22.5375", "longitude": "-168.6986" } }

其中iss_position.latitude与iss_position.longitude即 ISS 当前经纬度。由于该接口是 1.4 讲 JSON 中学习fetch()加载 JSON 数据的同一数据源,本讲正好可以把上一讲“用 fetch 解析 JSON”的能力直接复用:先用fetch()拿到 JSON,再把坐标交给 Leaflet 渲染。

课程在 1.6 讲.md) 中进一步说明:ISS 每秒都在移动,因此需要配合setInterval()周期性重新请求接口并更新 DOM。本讲完成“首次加载并标记”,下一讲完成“周期刷新”,两者共同构成完整方案。

四、核心实战:把 ISS 坐标渲染为地图标记

4.1 基础方案:直接使用 Marker

在fetch()回调中把经纬度转换为L.marker:

const url = 'https://api.wheretheiss.at/v1/satellites/25544'; async function getISS() { const response = await fetch(url); const data = await response.json(); const { latitude, longitude } = data.iss_position; const marker = L.marker([latitude, longitude]).addTo(mymap); marker.bindPopup('ISS 当前位置').openPopup(); } getISS();

关键点:

  • L.marker([lat, lng])在地图经纬度坐标处创建标记;
  • .addTo(mymap)把标记加入地图图层;
  • .bindPopup(...).openPopup()绑定并弹出信息窗,便于展示数据详情。

需要说明的是,ISS 坐标每秒钟都在变化,直接反复addTo会堆积大量 marker;更稳妥的做法是在下一次刷新时移除旧 marker 再创建新的,或直接更新 marker 的位置(marker.setLatLng([lat, lng])),这正是 1.6 讲 setInterval() 刷新数据.md) 要解决的持续更新问题。

4.2 进阶方案:p5.js + Mappa 绘制动态点

仓库中的真实可视化 CC_109_subscriber_map/P5/sketch.js 展示了另一种“地图 + 数据点”的整合思路:以 p5.js 画布叠加在 Leaflet 瓦片之上,用latLngToPixel()把经纬度换算成画布像素坐标后自由绘制。其核心调用链为:

const mappa = new Mappa('Leaflet'); let trainMap; function setup() { canvas = createCanvas(800, 600); trainMap = mappa.tileMap(options); // 依据 options 创建瓦片地图 trainMap.overlay(canvas); // 把 p5 画布叠加到地图上 } function draw() { clear(); for (let country of data) { const pix = trainMap.latLngToPixel(country.lat, country.lon); // 用画布椭圆绘制数据点,点径随缩放级别缩放 ellipse(pix.x, pix.y, country.diameter * pow(2, trainMap.zoom())); } }

该示例还体现了两个与地图可视化强相关的工程细节:

  1. 经纬度数据清洗:数据来自 subscribers_geo.csv(含country_id、subscribers等列),代码用 countries.json(国家代码 → 经纬度映射)把国家代码转换为坐标,过滤掉无法匹配的行;
  2. 缩放感知绘制:点径 = 基础直径 ×pow(2, zoom),即放大地图时数据点同步变大,避免“视觉上消失”。

这套“瓦片地图 + canvas 叠加 + 经纬度像素换算”的模式,尤其适合大量数据点的自定义可视化;而单点标记(如 ISS)则直接用L.marker更简洁。

五、效果与后续延伸:从单标记到数据可视化

在 CC_109_subscriber_map 对应的编码挑战中,作者用同一套 Leaflet 底层技术完成了“50 万订阅者全球分布图”——把每个国家的订阅者数量映射为地图上不同直径的圆点。这证明 Leaflet 不仅能承载单个实时标记(ISS),也能承载成千上万的数据点聚合可视化。

此外,课程 3.3 讲 Mapping Database Entries with Leaflet.js 是本讲的直接进阶:它把“地理定位 → 存数据库 → Leaflet 地图标记”整条链路串起来,将用户签到时上报的经纬度批量渲染到地图上。社区贡献中还出现了基于地图 + 实时数据的完整项目案例(如法兰克福机场实时航班雷达),可作为学完本讲后的拓展方向参考。

六、小结与建议练习

本讲的技术要点可归纳为一条清晰的调用链:

fetch() 获取 JSON(ISS 经纬度) → L.map 初始化地图容器 → L.tileLayer 指定瓦片底图 → L.marker 放置标记

建议的练习路径:

  1. 先复现本讲:用L.map+L.tileLayer+L.marker把 ISS 首次位置标出来;
  2. 再结合 1.6 讲.md):用setInterval()每秒刷新并用setLatLng()更新 marker,观察 ISS 轨迹;
  3. 最后参考 CC_109_subscriber_map/P5/sketch.js 的latLngToPixel模式,尝试把一组 CSV/JSON 坐标渲染成自定义数据点,并向 3.3 讲 的“数据库 → 地图”完整链路进阶。

需要注意的是:本讲为纯客户端实现,打开 HTML 即可运行,但fetch()访问第三方接口依赖网络与接口可用性;瓦片底图同样依赖外部瓦片服务,离线环境下地图将无法渲染。

  • 教程
  • 文档
  • 示例工程

【免费下载链接】website-archive

Archive of the Coding Train website (first version)

项目地址:https://gitcode.com/gh_mirrors/we/website-archive
点击查看免费下载
上一篇:英雄联盟Akari助手:从青铜到王者的智能效率革命实战宝典
下一篇:Bebas Neue:当几何美学遇见开源自由

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询