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

标注挤成一坨,text-allow-overlap 一开就全乱了

先看结论

城市名互相压住,打开允许重叠后,八百个名字同时糊在屏幕上。

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

现象

一个含 823 个 POI 的图层,text-field 用 ["get","name"]。 默认配置下只有零星几十个标注显示,其余被引擎自动隐藏,看起来「少了数据」。 加上 "text-allow-overlap": true 后,823 个名字全部出现, 在 10 级缩放下互相遮盖,完全无法阅读。

原因

Mapbox GL 的标注层内置碰撞检测:同一图层内,后放置的标注如果与已放置的标注 包围盒相交,就被丢弃。这一过程按屏幕像素计算, 所以缩放级别越高、标注越稀疏。

text-allow-overlap 关闭碰撞检测,等于放弃排版, 所有标注无差别叠加。它不是「解决拥挤」,只是「隐藏拥挤」。

配置行为适用
默认碰撞即隐藏,数量随缩放变化通用
text-allow-overlap: true全部显示,互相遮盖点数很少时
text-padding: 4加大碰撞间距减轻拥挤
分级 filter按 zoom 与等级筛要素推荐

排查过程

  1. queryRenderedFeatures 与 querySourceFeatures 的数量差,就是被碰撞隐藏的数量。
  2. 看是否误设了 text-allow-overlap 或 text-ignore-placement。
  3. 检查 symbol-placement 是否被设成 line,线状排布会让短名称互相挤。
  4. 确认 text-size 是否随缩放线性变大,过大的字号会加剧碰撞。
const rendered = map.queryRenderedFeatures({ layers: ['poi-label'] }).length;
const total = map.querySourceFeatures('poi').length;
console.log(rendered, total);   // 68 823  -> 755 个被碰撞隐藏

解决方案

用分级筛选与字号插值控制密度,把「显示多少个」交给 zoom,而不是交给重叠开关。

map.addLayer({
  id: 'poi-label',
  type: 'symbol',
  source: 'poi',
  minzoom: 9,
  filter: ['>=', ['get', 'rank'], 1],        // rank 1 最重要
  layout: {
    'text-field': ['get', 'name'],
    'text-size': ['interpolate', ['linear'], ['zoom'], 9, 11, 14, 14, 18, 17],
    'text-padding': 6,
    'text-allow-overlap': false,
    'text-ignore-placement': false,
    'text-max-width': 8,
    'text-anchor': 'top',
    'text-offset': [0, 0.6]
  }
});

// 缩放变化时切换等级,逐级放出更多标注
map.on('zoomend', () => {
  const z = map.getZoom();
  const minRank = z >= 14 ? 1 : z >= 12 ? 2 : 3;
  map.setFilter('poi-label', ['>=', ['get', 'rank'], minRank]);
});

验证

10 级时显示约 60 个标注,13 级约 200 个,16 级 500 个以上, 任意两个标注的包围盒不重叠;拖动地图时标注不闪烁跳动。

console.assert(map.getLayer('poi-label').layout['text-allow-overlap'] === false, '仍允许重叠');
const r = map.queryRenderedFeatures({ layers: ['poi-label'] });
console.assert(r.length > 0 && r.length < 823, '筛选未生效');

适用版本

库版本说明
Mapbox GL JS2.15 / 3.xtext-padding 单位为像素
MapLibre GL JS3.x / 4.x行为一致
Leaflet1.9.x无内置碰撞,需插件如 Leaflet.LabelTextCollision
引用本文

经纬志(2026)。《标注挤成一坨,text-allow-overlap 一开就全乱了》。https://www.jingweizhi.com/cookbook/label-overlap.html(访问日期 2026-11-03)。