MapLibre 学习指南:文章导航
在线预览地址:env-00jy66xyyn4y-static.normal.cloudstatic.cn/maplibre-ba…
base 代码仓库地址:
- Gitee:gitee.com/JuliusDeng/…
- GitHub:github.com/xwdeng001/m…
如果这个系列对你有帮助,欢迎给仓库点一个 Star,代码仓库可以拉取到完整的学习代码,在docs目录下有规划良好的.md学习文档,希望可以帮助到你(请给个免费的start哦)。你的支持是我持续更新和完善 MapLibre 学习内容的动力,也能帮助更多正在学习 WebGIS / MapLibre 的前端同学找到这份资料。[个人微信: 1576554007 欢迎一起学习交流]
第一阶段:入门基础(第 1-4 节)
| 节次 | 标题 | 核心内容 | 文档路径 |
|---|---|---|---|
| 01 | 认识 MapLibre GL JS | MapLibre 简介与生态、与 Mapbox 的关系、开源许可、应用场景、与其他地图库(Leaflet/OpenLayers/Cesium)对比 | src/docs/stage1/01.认识MapLibre.md |
| 02 | 环境搭建与第一张地图 | Vue3+Vite 项目创建、安装 MapLibre GL JS、创建第一张地图(Map 构造函数参数详解)、地图容器与响应式尺寸 | src/docs/stage1/02.环境搭建与第一张地图.md |
| 03 | 地图基础操作 | 缩放/平移/旋转/倾斜、flyTo/easeTo/jumpTo 动画方法、fitBounds 自适应范围、地图事件监听(click/move/zoom/load) | src/docs/stage1/03.地图基础操作.md |
| 04 | 地图控件 | NavigationControl、ScaleControl、GeolocateControl、FullscreenControl、AttributionControl、自定义控件(IControl 接口) | src/docs/stage1/04.地图控件.md |
04. 地图控件
概述
MapLibre GL JS 内置了多种地图控件,同时提供 IControl 接口用于创建自定义控件。本节学习:
- 5 种内置控件的使用
- 控件位置管理
- 自定义控件开发(IControl 接口)
添加和移除控件
// 添加控件
map.addControl(control, position?)
// 移除控件
map.removeControl(control)
控件位置
支持 4 个位置,默认 'top-right':
┌──────────────────────────────────┐
│ top-left top-right │
│ │
│ 地图区域 │
│ │
│ bottom-left bottom-right │
└──────────────────────────────────┘
内置控件详解
1. NavigationControl — 导航控件
提供缩放按钮(+/-)和指南针按钮。
const nav = new maplibregl.NavigationControl({
showCompass: true, // 显示指南针(默认 true)
showZoom: true, // 显示缩放按钮(默认 true)
visualizePitch: true // 指南针是否可视化倾斜角度(默认 false)
})
map.addControl(nav, 'top-right')
功能说明:
- 点击
+/-缩放地图 - 点击指南针重置为正北
- 拖拽指南针可旋转地图
2. ScaleControl — 比例尺控件
显示当前缩放级别对应的比例尺。
const scale = new maplibregl.ScaleControl({
maxWidth: 150, // 比例尺最大宽度(像素),默认 100
unit: 'metric' // 单位:'metric'(公制) | 'imperial'(英制) | 'nautical'(海里)
})
map.addControl(scale, 'bottom-left')
特点:地图缩放时比例尺会自动更新。
3. FullscreenControl — 全屏控件
切换地图为全屏模式。
const fullscreen = new maplibregl.FullscreenControl({
container: document.querySelector('#map') // 可选,指定全屏的容器
})
map.addControl(fullscreen, 'top-right')
⚠️ 部分浏览器/iframe 中可能不支持全屏 API。
4. GeolocateControl — 定位控件
获取用户的地理位置并在地图上标注。
const geolocate = new maplibregl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true // 启用高精度定位
},
trackUserLocation: true, // 持续追踪用户位置
showUserHeading: true // 显示用户朝向
})
map.addControl(geolocate, 'top-right')
// 监听定位事件
geolocate.on('geolocate', (e) => {
console.log('定位成功:', e.coords.longitude, e.coords.latitude)
})
geolocate.on('error', (e) => {
console.error('定位失败:', e.message)
})
⚠️ 需要 HTTPS 环境才能使用定位功能(localhost 除外)。
5. AttributionControl — 归属控件
显示地图数据的版权归属信息。
// 默认已自动添加,可通过构造参数禁用后手动添加
const map = new maplibregl.Map({
attributionControl: false // 禁用默认的归属控件
})
// 手动添加自定义归属
const attribution = new maplibregl.AttributionControl({
compact: true, // 折叠模式
customAttribution: '© 我的地图项目' // 自定义归属文本
})
map.addControl(attribution, 'bottom-right')
自定义控件(IControl 接口)
MapLibre 提供 IControl 接口,只需实现两个方法:
interface IControl {
onAdd(map: Map): HTMLElement // 添加时调用,返回控件 DOM
onRemove(map: Map): void // 移除时调用,清理资源
}
示例:坐标显示控件
class CoordinateControl implements maplibregl.IControl {
_map: maplibregl.Map | undefined
_container: HTMLElement | undefined
onAdd(map: maplibregl.Map): HTMLElement {
this._map = map
// 创建控件容器
this._container = document.createElement('div')
this._container.className = 'maplibregl-ctrl maplibregl-ctrl-group'
this._container.style.cssText = `
padding: 6px 10px;
font-size: 12px;
background: #fff;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0,0,0,0.2);
`
// 监听地图移动,更新坐标
const update = () => {
if (!this._map || !this._container) return
const center = this._map.getCenter()
const zoom = this._map.getZoom()
this._container.innerHTML = `
📍 ${center.lng.toFixed(4)}, ${center.lat.toFixed(4)}<br/>
🔍 Zoom: ${zoom.toFixed(2)}
`
}
map.on('move', update)
update()
return this._container
}
onRemove(): void {
this._container?.parentNode?.removeChild(this._container)
this._map = undefined
}
}
// 使用
map.addControl(new CoordinateControl(), 'bottom-right')
示例:一键回到初始位置
class HomeControl implements maplibregl.IControl {
_map: maplibregl.Map | undefined
_container: HTMLElement | undefined
_homeCenter: [number, number]
_homeZoom: number
constructor(center: [number, number], zoom: number) {
this._homeCenter = center
this._homeZoom = zoom
}
onAdd(map: maplibregl.Map): HTMLElement {
this._map = map
this._container = document.createElement('div')
this._container.className = 'maplibregl-ctrl maplibregl-ctrl-group'
const button = document.createElement('button')
button.type = 'button'
button.title = '回到初始位置'
button.innerHTML = '🏠'
button.style.cssText = 'width:30px;height:30px;cursor:pointer;font-size:16px;border:none;background:#fff;'
button.addEventListener('click', () => {
this._map?.flyTo({
center: this._homeCenter,
zoom: this._homeZoom
})
})
this._container.appendChild(button)
return this._container
}
onRemove(): void {
this._container?.parentNode?.removeChild(this._container)
this._map = undefined
}
}
// 使用
map.addControl(new HomeControl([116.39, 39.91], 10), 'top-left')
控件样式定制
使用 CSS 覆盖内置控件样式
/* 修改导航控件按钮大小 */
.maplibregl-ctrl-zoom-in,
.maplibregl-ctrl-zoom-out {
width: 36px !important;
height: 36px !important;
}
/* 修改比例尺样式 */
.maplibregl-ctrl-scale {
background: rgba(0, 0, 0, 0.6) !important;
color: #fff !important;
border-color: #fff !important;
font-size: 11px !important;
}
/* 自定义控件容器阴影 */
.maplibregl-ctrl-group {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;
border-radius: 8px !important;
}
自定义控件使用 Vue 组件
对于复杂的自定义控件,可以在 onAdd 中挂载 Vue 组件:
import { createApp } from 'vue'
import MyControlComponent from './MyControl.vue'
class VueControl implements maplibregl.IControl {
_container: HTMLElement | undefined
_app: any
onAdd(map: maplibregl.Map): HTMLElement {
this._container = document.createElement('div')
this._app = createApp(MyControlComponent, { map })
this._app.mount(this._container)
return this._container
}
onRemove(): void {
this._app?.unmount()
this._container?.parentNode?.removeChild(this._container)
}
}
控件最佳实践
- 合理安排位置:导航控件放右上角,比例尺放左下角,避免重叠
- 控件不宜过多:3-5 个为宜,过多会干扰地图交互
- 移动端适配:移动端可以隐藏部分控件,保持界面简洁
- 组件卸载:切换路由时要
removeControl或map.remove()避免内存泄漏 - 样式类名规范:自定义控件容器添加
maplibregl-ctrl类名,保持与内置控件一致的样式
本课小结
- 5 种内置控件:Navigation、Scale、Fullscreen、Geolocate、Attribution
- 控件通过
addControl(ctrl, position)添加,支持 4 个位置 - 自定义控件实现
IControl接口(onAdd返回 DOM,onRemove清理) - 可以使用 CSS 覆盖内置控件样式
- 复杂控件可在
onAdd中挂载 Vue 组件
📌 上一节:03. 地图基础操作 📌 下一节:05. 地图样式详解