📌 学习目标
- 掌握绘制GeoJSON点的实现方法
- 理解相关API的使用
- 能够独立完成类似功能开发
🎯 核心概念
在地图上绘制GeoJSON点。
💻 完 整 代 码
代码示例
js
const map = new maplibregl.Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json',
center: [0, 0],
zoom: 1
});
map.on('load', async () => {
// 添加图像作为自定义标记图标
const image = await map.loadImage('https://maplibre.org/maplibre-gl-js/docs/assets/osgeo-logo.png');
map.addImage('custom-marker', image.data);
// 添加一个GeoJSON源,包含15个点的
map.addSource('conferences', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [100.4933, 13.7551]
},
'properties': {'year': '2004'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [6.6523, 46.5535]
},
'properties': {'year': '2006'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-123.3596, 48.4268]
},
'properties': {'year': '2007'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [18.4264, -33.9224]
},
'properties': {'year': '2008'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [151.195, -33.8552]
},
'properties': {'year': '2009'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [2.1404, 41.3925]
},
'properties': {'year': '2010'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-104.8548, 39.7644]
},
'properties': {'year': '2011'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-1.1665, 52.9539]
},
'properties': {'year': '2013'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-122.6544, 45.5428]
},
'properties': {'year': '2014'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [126.974, 37.5651]
},
'properties': {'year': '2015'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [7.1112, 50.7255]
},
'properties': {'year': '2016'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-71.0314, 42.3539]
},
'properties': {'year': '2017'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [39.2794, -6.8173]
},
'properties': {'year': '2018'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [26.0961, 44.4379]
},
'properties': {'year': '2019'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-114.0879, 51.0279]
},
'properties': {'year': '2020'}
}
]
}
});
// 添加一个符号图层(自定义标记)
map.addLayer({
'id': 'conferences',
'type': 'symbol',
'source': 'conferences',
'layout': {
'icon-image': 'custom-marker',
// 从源的year属性中获取年份
'text-field': ['get', 'year'],
'text-font': [ 'Noto Sans Regular' ],
'text-offset': [0, 1.25],
'text-anchor': 'top'
}
});
});
代码示例
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Draw GeoJSON points</title>
<meta property="og:description" content="将 GeoJSON 集合中的点绘制到地图上。" />
<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>
const map = new maplibregl.Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json',
center: [0, 0],
zoom: 1
});
map.on('load', async () => {
// 添加一个图像作为自定义标记
const image = await map.loadImage('https://maplibre.org/maplibre-gl-js/docs/assets/osgeo-logo.png');
map.addImage('custom-marker', image.data);
// 添加一个包含15个点的GeoJSON源
map.addSource('conferences', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [100.4933, 13.7551]
},
'properties': {'year': '2004'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [6.6523, 46.5535]
},
'properties': {'year': '2006'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-123.3596, 48.4268]
},
'properties': {'year': '2007'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [18.4264, -33.9224]
},
'properties': {'year': '2008'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [151.195, -33.8552]
},
'properties': {'year': '2009'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [2.1404, 41.3925]
},
'properties': {'year': '2010'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-104.8548, 39.7644]
},
'properties': {'year': '2011'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-1.1665, 52.9539]
},
'properties': {'year': '2013'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-122.6544, 45.5428]
},
'properties': {'year': '2014'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [126.974, 37.5651]
},
'properties': {'year': '2015'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [7.1112, 50.7255]
},
'properties': {'year': '2016'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-71.0314, 42.3539]
},
'properties': {'year': '2017'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [39.2794, -6.8173]
},
'properties': {'year': '2018'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [26.0961, 44.4379]
},
'properties': {'year': '2019'}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-114.0879, 51.0279]
},
'properties': {'year': '2020'}
}
]
}
});
// 添加一个符号图层
map.addLayer({
'id': 'conferences',
'type': 'symbol',
'source': 'conferences',
'layout': {
'icon-image': 'custom-marker',
// 从源的"year"属性获取年份
'text-field': ['get', 'year'],
'text-font': [ 'Noto Sans Regular' ],
'text-offset': [0, 1.25],
'text-anchor': 'top'
}
});
});
</script>
</body>
</html>
🔍 代码解析
1. 初始化地图
使用 new maplibregl.Map() 创建地图实例,配置基本参数。本示例中心点设置在全球视图(0, 0)。
2. 加载自定义图标
使用 map.loadImage() 异步加载远程图片,然后通过 map.addImage() 将其注册为自定义标记图标。
3. 添加GeoJSON数据源
通过 map.addSource() 添加包含15个点的GeoJSON数据源,每个点代表一个会议举办地点,包含年份属性。
4. 添加符号图层
使用 symbol 类型图层,配置:
icon-image: 使用自定义图标text-field: 使用表达式['get', 'year']从属性获取年份text-offset: 文字偏移,避免与图标重叠
⚙️ 参数说明
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| container | string | 是 | 地图容器ID |
| style | string | 是 | 地图样式URL |
| center | number, number | 否 | 初始中心点,默认0, 0 |
| zoom | number | 否 | 初始缩放级别,默认0 |
symbol 图层 layout 属性
| 属性 | 类型 | 说明 |
|---|---|---|
| icon-image | string | 使用的图标名称 |
| text-field | string/expression | 显示的文字内容 |
| text-font | array | 字体名称数组 |
| text-offset | number, number | 文字偏移 x, y |
| text-anchor | string | 文字锚点位置 |
🎨 效果说明

运行代码后:
- 地图显示全球视图(中心点 0, 0,缩放级别1)
- 15个会议地点以自定义图标标记显示
- 每个标记下方显示对应的年份文字
- 用户可正常交互(拖拽、缩放、旋转)
💡 常 见 问 题
Q1: 如何使用自定义图标?
A: 先使用 map.loadImage() 加载图片,再用 map.addImage() 注册,最后在图层中引用:
javascript
const image = await map.loadImage('path/to/icon.png');
map.addImage('custom-marker', image.data);
Q2: 如何从GeoJSON属性获取值?
A: 使用表达式 ['get', 'propertyName']:
javascript
'text-field': ['get', 'year']
Q3: 如何调整文字位置?
A: 使用 text-offset 属性调整偏移,使用 text-anchor 设置锚点。
📝 练习任务
- 基础练习:修改自定义图标的URL,更换为其他图标
- 进阶挑战:根据年份属性设置不同颜色的标记
- 拓展思考:如何添加点击事件显示详细信息?
🌟 最佳实践
- 图标预加载: 在地图加载完成后再加载图标,避免异步问题
- 表达式使用: 使用表达式动态获取属性值,提高代码灵活性
- 性能优化: 大量点数据时考虑使用聚类(cluster)功能
- 响应式设计: 根据缩放级别调整图标大小和文字显示
🔗 延伸阅读
- Map API文档
- MapLibre GL JS 官方文档
- 下一课预告:将继续学习地图图层的基础知识
本文是MapLibre GL JS实践课程系列的一部分,欢迎关注收藏