📈 GH Trending Explorer 🎲 Surprise me

← all repos

william-xue / selection-drag-engine

git clone https://github.com/william-xue/selection-drag-engine.git

Renderer-agnostic rubberband selection and multi-drag engine: rAF coalescing, drag snapshot, preview/commit split. From X6 issue 4823.

+0
stars, 24h · #31,143
+~0
stars, 7 days · #31,618
+101
stars, 30 days · #4,851
92
★ total
0
forks · 0 open issues

Star history (as recorded here)

2026-10-20 · 101 ★ 2026-10-22 · 92 ★
LanguageJavaScript
LicenseMIT
Created2026-09-23 (29d ago)
Last push29d ago
Watchers0
OwnerUser

GitHub topics

Links

README excerpt
# Selection Drag Engine
渲染器无关的框选 / 多选拖拽引擎。来自 X6 issue 4823 的大画布拖拽性能经验,核心不绑定 X6、DOM 或任何具体渲染器。
三条性能保证(也是全部设计动机):
1. **rAF 合帧**:高频 `pointermove` 只累计位移,每帧最多 flush 一次。
2. **拖拽快照**:pointerdown 一次性冻结"要动谁",拖动中零重复计算。
3. **preview / commit 分离**:拖动中只动预览层,真实模型只在 `pointerup` 提交一次。
## 运行
 [code] 
Demo:`http://127.0.0.1:5173/demos/svg-selection-demo.html`(1000 个 SVG 对象,面板实时显示 pointermove / rAF flush / commit 次数与帧耗时)。
## 接入:实现一个 adapter
引擎本身零依赖;宿主只需注入一个 adapter 对象(可参考 `src/svg-selection-adapter.js`,136 行):
 [code] 
### adapter 契约
| 方法 | 调用时机 | 职责 |
|---|---|---|
| `hitTest(rect, { mode })` | **仅 pointerup** | 返回框选命中的 id 列表;`mode: 'intersects' \| 'contains'` |
| `setSelection(ids)` | 选择集变化时 | 应用新选择集 |
| `getSelection()` | 可选 | 返回当前选择集;不实现则用引擎内部状态 |
| `createDragSnapshot(ids)` | pointerdown | 冻结选中对象的可变副本(引擎不解释其结构,只透传) |
| `beginDragPreview(snapshot)` | pointerdown 后 | 建立预览层(clone / 遮罩 / 半透明,宿主自定) |
| `previewDrag(snapshot, delta)` | **每帧最多 1 次** | 只更新预览层 transform;必须廉价,禁止写真实模型 |
| `commitDrag(snapshot, delta)` | **仅 pointerup** | 把 `delta` 应用到真实数据与渲染;全拖拽唯一一次 |
| `endDragPreview(snapshot)` | pointerup / cancel | 销毁预览层、恢复源对象状态 |
| `renderRubberband(rect \| null)` | 框选期间每帧最多 1 次 | 画/隐藏橡皮筋矩形;`null` 表示隐藏 |
实现守则:
- `previewDrag` 里**只改 transform**(或等价的廉价属性),不遍历业务数据、不发事件。
- 所有真实写入收敛到 `commitDrag`;`hitTest` 只在抬起时跑——O(n) 只付一次。
- 忽略引擎在非 `pointerup` 时刻的任意中间态。
## 边界(非目标)
- 已实现:框选、多选、拖拽预览、拖拽提交、指标回调。
- 未实现(按需自加):resize / rotate、edge routing、undo/redo、spatial index(当前 hitTest 为 O(n),百~千级对象够用)、DOM/Canvas adapter。
- 框选命中允许 O(n),但只发生在框选结束时;snapshot / commit 允许 O(k),k 为选中数量。
## 目录
- `src/selection-drag-engine.js` — 状态机 + rAF 合帧核心(引擎唯一必读文件)
- `src/svg-selection-adapter.js` — SVG adapter 参考实现
- `src/geometry.js` / `src/raf-scheduler.js` — 矩形工具、rAF 适配
- `tests/selection-drag-engine.test.js` — 合帧、命中时机、几何行为
- `docs/design.md` — 设计动机与性能约束
- `demos/svg-selection-demo.html` — 1000 对象实例
## 背景
X6 issue 4823:大数据量框选拖拽时,旧实现把"查图 + 移动 + 更新高亮框"全挂在高频 `mousemove` 上,成本 = 事件数 × 选中数。本库把同一套修复(合帧 / 缓存 / 冻结)固化为独立内核。背景分析见 issue 讨论。
## License
MIT