- 教程
- 文档
- 示例工程
【免费下载链接】website-archive
Archive of the Coding Train website (first version)
导读
本篇文章对应《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:web
fetch()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: '© <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())); } }该示例还体现了两个与地图可视化强相关的工程细节:
- 经纬度数据清洗:数据来自 subscribers_geo.csv(含
country_id、subscribers等列),代码用 countries.json(国家代码 → 经纬度映射)把国家代码转换为坐标,过滤掉无法匹配的行; - 缩放感知绘制:点径 = 基础直径 ×
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 放置标记建议的练习路径:
- 先复现本讲:用
L.map+L.tileLayer+L.marker把 ISS 首次位置标出来; - 再结合 1.6 讲.md):用
setInterval()每秒刷新并用setLatLng()更新 marker,观察 ISS 轨迹; - 最后参考 CC_109_subscriber_map/P5/sketch.js 的
latLngToPixel模式,尝试把一组 CSV/JSON 坐标渲染成自定义数据点,并向 3.3 讲 的“数据库 → 地图”完整链路进阶。
需要注意的是:本讲为纯客户端实现,打开 HTML 即可运行,但fetch()访问第三方接口依赖网络与接口可用性;瓦片底图同样依赖外部瓦片服务,离线环境下地图将无法渲染。
- 教程
- 文档
- 示例工程
【免费下载链接】website-archive
Archive of the Coding Train website (first version)
相关推荐
深入探索Leafmap:Python地理空间分析与交互式地图绘制指南
深入探索Leafmap:Python地理空间分析与交互式地图绘制指南 什么是Leafmap? Leafmap是一个基于Python的开源库,专为地理空间数据分析
数据分析folium 快速上手:用 Python 数据能力驱动 Leaflet.js 交互式地图
folium 快速上手:用 Python 数据能力驱动 Leaflet.js 交互式地图 folium 是 Python 生态中的地理可视化利器:它把 Pyth
数据可视化数据分析GISFolium 快速上手:用 Python 与 Leaflet.js 构建交互式地图的完整指南
Folium 快速上手:用 Python 与 Leaflet.js 构建交互式地图的完整指南 导读 Folium 是 Python 生态中基于 Leaflet.
数据可视化数据分析GIS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考