必须用 Canvas/WebGL 批量绘制替代 DOM Marker:高德用 CanvasLayer,百度用 CustomLayer,Leaflet 用 VectorGrid/glify,deck.gl 最灵活;需服务端分片、Worker 解析、空间索引与视口更新。
HTML5 地图上一次性渲染百万级点标记(Marker)必然卡死,这不是优化问题,而是浏览器渲染模型的硬限制——你不能靠“调优”绕过 DOM 节点数量与 Canvas 绘制能力的物理瓶颈。
为什么直接加百万 Marker 必然卡?
主流地图 SDK(如高德、百度、腾讯、Leaflet + L.Marker)默认为每个点创建独立 DOM 元素或 Canvas 图形对象。百万级节点会触发:
- DOM 树膨胀至数百万节点(含事件监听器、样式计算、重排重绘),Chrome 通常在 10 万级就明显掉帧
- GPU 内存溢出或浏览器主动 kill 渲染进程(尤其移动端)
- 地图 SDK 自身的碰撞检测、聚合逻辑在未降级时呈 O(n²) 复杂度
必须用 canvas 或 WebGL 图层替代 DOM 标记
真实可行路径只有一条:放弃逐点创建 Marker,改用底层绘制接口批量处理。不同 SDK 方案差异大:
- 高德地图:用
AMap.CanvasLayer,自己在canvas上用ctx.fillRect()或ctx.drawImage()画点,配合map.getPixelFromLngLat()做坐标转换 -
百度地图:用
BMapGL.CustomLayer(需开启 WebGL 模式),传入draw回调,在gl上用着色器绘制点精灵(point sprite) - Leaflet:用
Leaflet.VectorGrid或Leaflet.glify,把点数据转成 GeoJSON + 着色器,交由 GPU 批量绘制 - 纯
WebGL方案(如 deck.gl +ScatterplotLayer):最灵活,支持千万级点,但需自行管理地图投影与缩放同步
数据必须预处理:不是“加载”,而是“分片 + 动态加载”
即使用了 WebGL,百万点原始数据(如 10MB GeoJSON)也会阻塞主线程解析。关键动作是: