以线要素为例,在 Mapbox GL JS 中,为线要素添加点击事件主要有两种常见方式,分别适用于不同的场景:直接监听地图的点击事件并判断是否点击到线,或者为图层添加交互式事件。
方法一:监听地图点击事件(通用方式)
这种方式通过监听整个地图的 click 事件,然后通过 queryRenderedFeatures 方法判断点击位置是否存在目标线要素,适用性更广。
<!doctype html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>监听地图点击事件(通用方式)</title> <!-- 引入Mapbox核心库 --> <link href="https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.css" rel="stylesheet" /> <script src="https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.js"></script> <!-- 引入Draw插件 --> <link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.css" /> <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.js"></script> <script src="./json/data.js"></script> <style> body { margin: 0; padding: 0; } #map { width: 100vw; height: 100vh; } </style> </head> <body> <div id="map"></div> <script> // 初始化地图 mapboxgl.accessToken = "Access Token"; const map = new mapboxgl.Map({ container: "map", style: "mapbox://styles/mapbox/satellite-v9", projection: "globe", center: [116.4074, 39.9042], // 地图中心点(北京) zoom: 19, }); // 地图加载完成后执行 map.on('load', () => { // 1. 添加线数据源 map.addSource('test-line', { type: 'geojson', data: { type: 'Feature', geometry: { type: 'LineString', coordinates: [ [116.38, 39.91], // 起点坐标 [116.42, 39.89] // 终点坐标 ] }, properties: { name: '测试线路', id: 'line-001' } } }); // 2. 添加线图层 map.addLayer({ id: 'test-line-layer', type: 'line', source: 'test-line', paint: { 'line-color': '#ff0000', // 线颜色 'line-width': 8 // 线宽度(宽度越大越容易点击到) } }); // 3. 监听地图点击事件 map.on('click', (e) => { // 查询点击位置的要素 const features = map.queryRenderedFeatures(e.point, { layers: ['test-line-layer'] // 指定只查询目标线图层 }); // 如果点击到了线要素 if (features.length > 0) { const lineFeature = features[0]; console.log('点击到了线要素:', lineFeature); // 触发自定义操作 alert(`你点击了【${lineFeature.properties.name}】,ID:${lineFeature.properties.id}`); } }); // 可选:添加鼠标悬停效果,提升交互体验 map.on('mousemove', (e) => { const features = map.queryRenderedFeatures(e.point, { layers: ['test-line-layer'] }); // 鼠标悬停在线上时改变光标样式 map.getCanvas().style.cursor = features.length > 0 ? 'pointer' : ''; }); }); </script> </body> </html>方法二:为图层添加交互式事件(更简洁)
Mapbox 支持直接为指定图层绑定 click 事件,代码更简洁,推荐优先使用。
<!doctype html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Mapbox 生成可编辑高亮新线(保留所有状态)</title> <!-- 引入Mapbox核心库 --> <link href="https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.css" rel="stylesheet" /> <script src="https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.js"></script> <!-- 引入Draw插件 --> <link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.css" /> <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.js"></script> <script src="./json/data.js"></script> <style> body { margin: 0; padding: 0; } #map { width: 100vw; height: 100vh; } .botton-container { position: fixed; top: 30px; right: 30px; z-index: 10; } .botton-container button { margin: 0 5px 10px 0; padding: 6px 12px; cursor: pointer; } </style> </head> <body> <div id="map"></div> <div class="botton-container"> <button id="drawPoint">绘制点</button> <button id="drawLine">绘制线</button> <button id="drawPolygon">绘制面</button> <button id="deleteFeature">删除选中</button> <button id="clearAll">清空所有</button> </div> <script> console.log("===data==="); console.log(data) // 初始化地图 mapboxgl.accessToken = "Access Token"; const map = new mapboxgl.Map({ container: "map", style: "mapbox://styles/mapbox/satellite-v9", projection: "globe", center: [116.38, 39.91], zoom: 19, }); // 初始化Draw插件 const draw = new MapboxDraw({ displayControlDefault: true, controls: { point: true, line_string: true, polygon: true, trash: true, combine_features: true, uncombine_features: true, }, }); map.addControl(draw, "top-left"); // 地图加载完成后执行:添加自定义图层、绑定按钮事件 map.on('load', () => { // 添加线数据源和图层(同上) map.addSource('test-line', { type: 'geojson', data: { type: 'Feature', geometry: { type: 'LineString', coordinates: [[116.38, 39.91], [116.42, 39.89]] }, properties: { name: '测试线路', id: 'line-001' } } }); map.addLayer({ id: 'test-line-layer', type: 'line', source: 'test-line', paint: { 'line-color': '#ff0000', 'line-width': 8 } }); // 直接为线图层绑定点击事件(核心代码) map.on('click', 'test-line-layer', (e) => { const lineFeature = e.features[0]; console.log('点击到线:', lineFeature); alert(`点击了线路:${lineFeature.properties.name}`); }); // 可选:添加点击时的弹窗(Popup) map.on('click', 'test-line-layer', (e) => { new mapboxgl.Popup() .setLngLat(e.lngLat) // 弹窗位置为点击位置 .setHTML(`<h3>${e.features[0].properties.name}</h3><p>ID:${e.features[0].properties.id}</p>`) .addTo(map); }); // 鼠标悬停效果 map.on('mouseenter', 'test-line-layer', () => { map.getCanvas().style.cursor = 'pointer'; }); map.on('mouseleave', 'test-line-layer', () => { map.getCanvas().style.cursor = ''; }); }); </script> </body> </html>方法三:为不同线要素添加独立交互(使用表达式)
// 添加包含多个线要素的图层 map.addSource('lines', { type: 'geojson', data: { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { id: 1, type: 'road', clickable: true }, geometry: { ... } }, { type: 'Feature', properties: { id: 2, type: 'river', clickable: false }, geometry: { ... } } ] } }); // 使用图层过滤只让可点击的线响应事件 map.on('click', 'lines', (e) => { const feature = e.features[0]; if (feature.properties.clickable) { console.log('可点击的线被点击:', feature); } });重要提示:
线宽度:确保线的宽度足够大,方便点击(建议至少 5-8px)
图层顺序:确保线图层在其他可点击图层之上
性能优化:如果线要素很多,考虑使用 queryRenderedFeatures 的第二个参数限制搜索范围:
map.queryRenderedFeatures(e.point, { layers: ['my-line-layer'], filter: ['==', 'type', 'road'] // 添加过滤器 });