经纬志
首页 / 实战手册 / 样式与渲染

sprite 里没有这个图标名,符号层直接不画

先看结论

icon-image 写了一个名字,地图上什么都不出现,也没有任何报错。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

一个 symbol 图层,layout['icon-image'] = 'poi-restaurant'。 地图上该点位完全不渲染,既没有图标,也没有文字。 网络面板里 sprite.json 与 sprite.png 都返回 200。

打开 sprite.json 搜索 poi-restaurant,找不到该键。

原因

Mapbox 的图标不是图片 URL,而是 sprite 表里的名字。 sprite.json 记录每个图标的尺寸与位置, sprite.png 是所有图标拼成的一张图。

引擎按名字查表,查不到时该符号被视为无法渲染, 整个符号(含文字)都被跳过,且不产生控制台错误。 名字区分大小写,也区分连字符与下划线:poi_restaurant 与 poi-restaurant 是两个不同的键。

引用值sprite 中的键结果
poi-restaurantpoi_restaurant不渲染
restaurantrestaurant正常
Restaurantrestaurant不渲染

排查过程

  1. 请求 sprite.json,搜索 icon-image 的实际值。
  2. 打印该图层 layout['icon-image'],注意是字符串还是表达式。
  3. 若用了 ['get','icon'],检查属性值是否与键名完全一致。
  4. 确认 sprite 版本与样式里的 sprite 路径一致,不要同时加载两份。
const sprite = await fetch('/sprite.json').then(r => r.json());
console.log(Object.keys(sprite));   // ['restaurant', 'hospital', 'parking', ...]

console.log(map.getLayer('poi').layout['icon-image']);   // 'poi-restaurant'
console.log('poi-restaurant' in sprite);                   // false

解决方案

图标名与 sprite 键严格对齐。数据里存图标名时,用白名单校验, 不匹配的退回通用图标。

// 生成 sprite(spritezero)
spritezero sprite ./icons
# 生成 sprite.json / sprite.png,键名取自文件名(不含扩展名)
# icons/restaurant.svg  ->  键 'restaurant'
// 图标名做一次白名单映射,避免脏数据导致整层符号消失
const ICONS = new Set(['restaurant', 'hospital', 'parking', 'school']);

fc.features.forEach(f => {
  const raw = f.properties.icon;
  f.properties.icon = ICONS.has(raw) ? raw : 'marker-default';
});

map.addLayer({
  id: 'poi',
  type: 'symbol',
  source: 'poi',
  layout: {
    'icon-image': ['get', 'icon'],
    'icon-size': 1,
    'icon-allow-overlap': true
  }
});

缺图标时不要依赖报错。Mapbox GL 对 sprite 缺失是静默的, 上线前用脚本把数据里的 icon 值与 sprite.json 的键做一次差集检查。

验证

数据中的所有 icon 值都能在 sprite.json 中找到; 地图上每个点位都显示图标,queryRenderedFeatures 数量与数据一致。

const missing = [...new Set(fc.features.map(f => f.properties.icon))]
  .filter(k => !(k in sprite));
console.assert(missing.length === 0, '缺图标:' + missing.join(','));

const r = map.queryRenderedFeatures({ layers: ['poi'] });
console.assert(r.length === fc.features.length, '仍有符号未渲染');

适用版本

组件版本说明
Mapbox GL JS2.15 / 3.xsprite 缺键时静默跳过整个符号
MapLibre GL JS3.x / 4.x行为一致
spritezero-cli1.3.0按文件名生成键,区分大小写
引用本文

经纬志(2026)。《sprite 里没有这个图标名,符号层直接不画》。https://www.jingweizhi.com/cookbook/sprite-icon-missing.html(访问日期 2026-11-03)。