经纬志
首页 / 实战手册 / 性能

标记点一多就卡

先看结论

三百个点还算流畅,八百个点开始掉帧,两千个点拖动像放幻灯片。这是矢量图层最常见的性能瓶颈。

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

现象

点位数量增长后,拖拽和缩放明显变卡,CPU 占用飙升。 打开性能面板可以看到大量 DOM 节点,或者每帧都在重绘矢量图层。

为什么会卡

Leaflet 的默认标记是真实的 DOM 元素。两千个标记就是两千个 DOM 节点, 每次地图移动都要重新计算它们的位置并写样式,浏览器要重排重绘两千次。 OpenLayers 的矢量层默认走 SVG 或 canvas,问题类似,只是瓶颈点在绘制调用上。

按数据量选方案

数据量方案预期效果
少于 300默认标记即可,注意用图层组管理无需优化
300–2000改用 canvas 渲染,或使用聚合可稳定流畅
2000–20000必须聚合,或只渲染当前视野可接受
20000 以上换 deck.gl 之类走 WebGL 的图层引擎十万级仍可满帧

方案一:改用 canvas 渲染

Leaflet 提供 preferCanvas,让矢量图层走 canvas 而不是 SVG,节点数不再随数据增长。

var map = L.map('map', {
  center: [39.9, 116.4],
  zoom: 11,
  preferCanvas: true
});

OpenLayers 侧在图层上关闭 SVG 渲染,同时关掉每个要素的独立样式,尽量共用同一个样式对象。

var layer = new ol.layer.Vector({
  source: source,
  style: sharedStyleObject,   // 共用一个样式,不要每条要素 new 一个
  updateWhileAnimating: false,
  updateWhileInteracting: false
});

方案二:只渲染当前视野

数据在视野外就完全不画。地图移动结束时重新筛选一次, 比全量渲染省一个数量级。

function refresh() {
  var bounds = map.getBounds();
  group.clearLayers();

  points.forEach(function (p) {
    if (bounds.contains([p.lat, p.lng])) {
      group.addLayer(makeMarker(p));
    }
  });
}

map.on('moveend', refresh);
refresh();

这个做法的代价是移动过程中会短暂空窗,需要在 moveend 后补画, 所以适合点位分布稀疏的场景。

方案三:聚合

Leaflet 用 markercluster 插件,OpenLayers 用官方的 Cluster 数据源。 聚合的本质是把临近的点合并成一个带数字的圆, 不仅提升性能,也让密集区域更可读。

var cluster = new ol.source.Cluster({
  distance: 40,          // 聚合半径,单位像素
  source: new ol.source.Vector({ features: features })
});

var layer = new ol.layer.Vector({
  source: cluster,
  style: function (feature) {
    var size = feature.get('features').length;
    return clusterStyle(size);   // 数量不同给不同大小的圆
  }
});

方案四:换渲染引擎

到几万点这个量级,任何基于 DOM 或 canvas 的方案都到顶了。 这时应该把可视化层换成 WebGL 实现,底图仍然可以是 Leaflet 或 MapLibre, 数据层交给 deck.gl 绘制。

排查顺序

  1. 先数清楚到底多少个点,不要凭感觉
  2. 少于 300 就别优化布局,多半是别的地方慢
  3. 300 以上先开 canvas 渲染,通常立竿见影
  4. 仍然卡就加视野裁剪或聚合
  5. 上万点直接换 WebGL 图层引擎

还有一个常被忽略的点:每给要素新建一个样式对象, 就等于让渲染层失去复用机会。几千个要素各自 new 一个 Style, 内存和绘制开销都会成倍增长。样式应该提前建好、反复使用。

引用本文

经纬志(2026)。《标记点一多就卡》。https://www.jingweizhi.com/cookbook/marker-performance.html(访问日期 2026-11-03)。