交互与控件
控件是加在容器上的 DOM 按钮,交互是地图对鼠标与触摸的响应。
MapLibre 把每个交互做成可独立开关的 handler,事件则通过
map.on() 统一分发。
内置控件
| 控件 | 作用 | 常用参数 |
|---|---|---|
NavigationControl | 缩放按钮与指南针 | showCompass、visualizePitch |
ScaleControl | 比例尺 | unit: 'metric'、maxWidth |
GeolocateControl | 定位按钮 | trackUserLocation、positionOptions |
AttributionControl | 版权信息 | compact |
TerrainControl | 地形开关 | source、exaggeration |
var map = new maplibregl.Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json',
center: [116.391263, 39.907359],
zoom: 5,
attributionControl: false // 先关掉,改用自定义位置
});
map.addControl(new maplibregl.NavigationControl({
showCompass: true,
visualizePitch: true
}), 'top-right');
map.addControl(new maplibregl.ScaleControl({
unit: 'metric',
maxWidth: 120
}), 'bottom-left');
map.addControl(new maplibregl.GeolocateControl({
positionOptions: { enableHighAccuracy: true },
trackUserLocation: true
}), 'top-right');
map.addControl(new maplibregl.AttributionControl({
compact: true
}), 'bottom-right');
位置参数只有四个:top-left、top-right、
bottom-left、bottom-right。同一角落多次添加时,
控件按添加顺序堆叠,DOM 顺序不影响它们在地图上的层级。
交互开关
每个交互都是一个 handler 对象,可以 enable()、
disable()、isEnabled()。
当业务需要「地图只读」时,逐个关掉比在容器上盖一层遮罩更可靠。
| handler | 默认 | 作用 |
|---|---|---|
dragPan | 开启 | 鼠标拖动与单指拖动平移 |
scrollZoom | 开启 | 滚轮缩放 |
dragRotate | 开启 | 右键或 Ctrl 拖动旋转与倾斜 |
doubleClickZoom | 开启 | 双击放大 |
touchZoomRotate | 开启 | 双指缩放与旋转 |
touchPitch | 开启 | 双指上下滑动改变倾角 |
boxZoom | 开启 | 按住 Shift 拖框放大 |
keyboard | 开启 | 方向键平移 |
// 内嵌在可滚动页面里的地图:保留拖动,关掉滚轮缩放
map.scrollZoom.disable();
map.doubleClickZoom.disable();
map.boxZoom.disable();
// 展示态:全部只读
function setReadOnly(readonly) {
['dragPan', 'scrollZoom', 'dragRotate', 'doubleClickZoom',
'touchZoomRotate', 'touchPitch', 'boxZoom', 'keyboard'
].forEach(function (name) {
if (readonly) map[name].disable();
else map[name].enable();
});
}
点击查询要素
事件本身不带要素信息,要拿到被点中的东西必须调用
queryRenderedFeatures。它查询的是当前已渲染的要素,
视野外的数据查不到。
map.on('click', function (e) {
var features = map.queryRenderedFeatures(e.point, {
layers: ['sites-circle'] // 限定图层,避免命中底图
});
if (features.length === 0) {
new maplibregl.Popup().remove();
return;
}
var f = features[0];
new maplibregl.Popup({ closeButton: false })
.setLngLat(f.geometry.coordinates)
.setHTML('<b>' + f.properties.name + '</b>')
.addTo(map);
});
// 图层级事件:直接拿到要素,且只在命中时触发
map.on('mouseenter', 'sites-circle', function () {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'sites-circle', function () {
map.getCanvas().style.cursor = '';
});
layers 参数非常关键。不限定图层时,点击会返回鼠标位置下所有图层的结果,
包括底图的国界、道路,取 features[0] 常常拿到不想处理的那个。
事件对象里有什么
| 字段 | 含义 | 注意 |
|---|---|---|
e.lngLat | 经纬度 | 顺序是 [lng, lat] |
e.point | 相对容器左上角的像素 | {x, y} |
e.features | 命中的要素数组 | 图层级事件里才有 |
e.originalEvent | 原生 DOM 事件 | 取 shiftKey 等修饰键 |
e.preventDefault() | 阻止默认行为 | 在 click 上不能阻止地图平移 |
注意事项
图层级监听在图层创建前绑定
map.on('click', 'layer-id', fn) 里的图层 id 必须已经存在。
在 load 之前绑定,事件永远不会触发,也不会报错。
queryRenderedFeatures 的高频调用
在 mousemove 里每帧查询要素,会拖慢整个渲染循环。
用 requestAnimationFrame 或时间间隔节流到 60 毫秒一次,
并把 layers 收窄到真正需要的图层。
控件被容器样式影响
控件按钮依赖 maplibre-gl.css 定位。页面里用全局
button { ... } 改写按钮样式,会把缩放按钮挤成方块。
用 .maplibregl-ctrl 前缀的类做局部覆盖。
经纬志(2026)。《交互与控件》。https://www.jingweizhi.com/maplibre/tutorial/interactions-controls.html(访问日期 2026-11-03)。