MapLibre GL地图鼠标悬浮添加图片报错及本地图片加载问题咨询
问题原因
- 两个报错均由重复创建资源导致:你将图片加载、数据源新增、图层新增的逻辑写在了高频触发的
mousemove事件回调中,鼠标每移动一次就会执行一次新增操作,同一个id的资源重复添加就会抛出冲突错误:- 首次触发事件时已经添加了名为
cat的图片资源,后续重复调用map.addImage('cat')触发图片已存在报错 - 首次触发事件时已经添加了id为
point的数据源,后续重复调用map.addSource('point')触发数据源id已存在报错
- 首次触发事件时已经添加了名为
- 额外隐藏问题:原有代码中GeoJSON点坐标写反了,GeoJSON规范要求Point坐标顺序为
[经度, 纬度],原有代码赋值为[纬度, 经度]会导致图标位置偏离鼠标位置。
修复后的完整代码
var map = new maplibregl.Map({ container: 'map', style: 'assets/data/basic/style.json', antialias: true, center: [-0.42, 8.22], zoom: 0, attributionControl: false, maxBounds: [[-171.87, -83.65], [188.31, 83.55]] }); map.on('load', function () { // 原有地震热力图、点图层逻辑保留 map.addSource('earthquakes', { 'type': 'geojson', 'data': 'assets/data/earthquakes.geojson' }); map.addLayer({ 'id': 'earthquakes-heat', 'type': 'heatmap', 'source': 'earthquakes', 'maxzoom': 9, 'paint': { 'heatmap-weight': [ 'interpolate', ['linear'], ['get', 'mag'], 0, 0, 6, 1 ], 'heatmap-intensity': [ 'interpolate', ['linear'], ['zoom'], 0, 1, 9, 3 ], 'heatmap-color': [ 'interpolate', ['linear'], ['heatmap-density'], 0, 'rgba(33,102,172,0)', 0.2, 'rgb(226,41,68)', 0.4, 'rgb(226,41,68)', 0.6, 'rgb(226,41,68)', 0.8, 'rgb(226,41,68)', 1, 'rgb(226,41,68)' ], 'heatmap-radius': [ 'interpolate', ['linear'], ['zoom'], 0, 2, 9, 20 ], 'heatmap-opacity': [ 'interpolate', ['linear'], ['zoom'], 7, 1, 9, 0 ] } }); map.addLayer({ 'id': 'earthquakes-point', 'type': 'circle', 'source': 'earthquakes', 'minzoom': 7, 'paint': { 'circle-radius': [ 'interpolate', ['linear'], ['zoom'], 7, ['interpolate', ['linear'], ['get', 'mag'], 1, 1, 6, 4 ], 16, ['interpolate', ['linear'], ['get', 'mag'], 1, 5, 6, 50 ] ], 'circle-color': [ 'interpolate', ['linear'], ['get', 'mag'], 1, 'rgba(33,102,172,0)', 2, 'rgb(103,169,207)', 3, 'rgb(209,229,240)', 4, 'rgb(253,219,199)', 5, 'rgb(239,138,98)', 6, 'rgb(178,24,43)' ], 'circle-stroke-color': 'white', 'circle-stroke-width': 1, 'circle-opacity': [ 'interpolate', ['linear'], ['zoom'], 7, 0, 8, 1 ] } }); // ========== 悬浮图标逻辑修改开始 ========== // 1. 提前加载图标,仅执行一次 map.loadImage( // 若要加载本地图片,这里替换为本地图片相对路径即可,例如 'assets/images/cat.png' 'https://docs.mapbox.com/mapbox-gl-js/assets/cat.png', (error, image) => { if (error) throw error; // 添加图片资源,仅执行一次 map.addImage('cat', image); // 2. 提前初始化空的点数据源,仅执行一次 map.addSource('hover-point', { 'type': 'geojson', 'data': { 'type': 'FeatureCollection', 'features': [] } }); // 3. 提前初始化图标图层,仅执行一次 map.addLayer({ 'id': 'hover-icon', 'type': 'symbol', 'source': 'hover-point', 'layout': { 'icon-image': 'cat', 'icon-size': 0.25 } }); // 4. 鼠标移动时仅更新数据源坐标,不重复创建资源 map.on('mousemove', function (e) { const coor = e.lngLat.wrap(); // 注意GeoJSON坐标顺序为 [经度, 纬度] const pointGeoJson = { 'type': 'FeatureCollection', 'features': [ { 'type': 'Feature', 'geometry': { 'type': 'Point', 'coordinates': [coor.lng, coor.lat] } } ] }; // 更新已有数据源的数据即可 map.getSource('hover-point').setData(pointGeoJson); }); } ); // ========== 悬浮图标逻辑修改结束 ========== });
本地图片加载说明
只需要将上述代码中map.loadImage的第一个参数替换为你本地图片的相对路径即可,例如你的图片存放在项目assets/img/custom-hover.png路径下,就写为'assets/img/custom-hover.png',只要路径匹配项目结构就能正常加载,无需额外配置。
内容的提问来源于stack exchange,提问作者Lahari
相关产品推荐
相关产品推荐

