You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MapLibre GL地图鼠标悬浮添加图片报错及本地图片加载问题咨询

问题原因
  • 两个报错均由重复创建资源导致:你将图片加载、数据源新增、图层新增的逻辑写在了高频触发的mousemove事件回调中,鼠标每移动一次就会执行一次新增操作,同一个id的资源重复添加就会抛出冲突错误:
    1. 首次触发事件时已经添加了名为cat的图片资源,后续重复调用map.addImage('cat')触发图片已存在报错
    2. 首次触发事件时已经添加了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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 09:36:03