Web Worker通过空间划分结构(网格桶/四叉树)在后台高效执行局部碰撞检测(范围查询),仅将精简结果传回主线程渲染,避免O(n²)卡顿。

大规模散点图中,成千上万个点之间若需实时判断“是否相邻过近”(比如防标签重叠、高亮冲突区域、交互反馈等),直接在主线程做两两距离计算(O(n²))会严重卡顿。Web Worker 是解法核心——它把密集的局部碰撞检测逻辑完全搬离渲染线程,只把结果(如哪些点发生了局部聚集、哪些需隐藏/偏移/聚合)传回主线程用于可视化。
明确“局部碰撞”的实际含义
散点图里一般不关心全局任意两点是否相撞,而是关注“某个点周围一定半径内是否存在其他点”。这本质是范围查询(range query),不是全量配对。Worker 中应聚焦于:
• 每个点的坐标(x, y)和检测半径 r
• 快速找出所有满足 distance(pᵢ, pⱼ) ≤ r 的点对(i ≠ j)
• 可选:按密度分组(如 3 点以上聚集为簇)、标记中心点或生成聚合 ID
用空间划分结构替代暴力遍历
纯循环比对在万级点时已不可行。Worker 内推荐两种轻量高效方案:
- 网格桶(Spatial Grid):将画布区域划分为边长为 r 的正方形网格;每个点落入对应格子;只需检查自身格子 + 8 个邻近格子内的点——平均复杂度降至 O(n·k),k 为平均每格点数
-
四叉树(Quadtree):适合点分布极不均匀的场景(如大量聚集+大片稀疏);构建开销略高,但查询更精准;Worker 中可用轻量实现(如
simple-quadtree类库或手写递归插入)
数据传递与通信设计要点
主线程不能把 Canvas 或 DOM 对象传给 Worker,只能传纯数据:
- 传入:点集数组
[{id: 1, x: 120.5, y: 87.2}, ...]+ 配置项{radius: 24, maxNeighbors: 5} - 传出:精简结果,例如
{clusters: [[1,5,9], [12,18]], isolated: [3,7,22]},避免传冗余坐标 - 优化:使用
Transferable Objects(如Float32Array存坐标)减少内存拷贝;尤其当点数超 10 万时效果明显
主线程如何配合才不掉帧
Worker 返回结果只是中间态,最终渲染必须由主线程完成:
- 不要等 Worker 完全算完再渲染——可先用上一帧结果维持视觉连续性
- 对动态散点图(如实时流数据),采用“滑动窗口”策略:Worker 每次只处理最近 N 个新增点 + 周边已有热点区域,而非全量重算
- 结果应用要克制:比如仅对被标记为“拥挤”的点添加 tooltip 提示或缩小尺寸,而不是逐点重绘整个图层

















