snap-ortho
本文回答:绘图捕捉 / 正交 / 对齐辅助线(guides),
snapOptions与 Alt / Ctrl / Backspace 快捷键。
一、开启捕捉
const draw = new vjmap.Draw.Tool({
snap: true, // 对象捕捉
guides: true, // 对齐辅助线:经过附近已有顶点的水平 / 竖直参考线(不是网格)
snapOptions: {
snapPx: 15, // 捕捉像素阈值(⚠️ CAD GeoProjection 下有效半径仅 ~5-10px,
// 且 zoom 无关——阈值换算用标准 mercator 米、距离量算走 CAD unproject,
// 两条缩放律不抵消;要更大半径需把 snapPx 调大约 2 倍)
snapToMidPoints: false, // 是否捕捉中点
snapVertexPriorityDistance: 1.25, // 顶点优先距离
snapGridPx: 2000 // 辅助线半长(像素),默认 2000
}
});
在 action API 里通过 api.getSnapFeatures:
await vjmap.Draw.actionDrawPoint(map, {
api: { getSnapFeatures: snapObj } // snapObj.features 是要捕捉的要素数组
});
二、快捷键(绘图时)
| 键 | 动作 |
|---|---|
Alt |
按住期间禁用捕捉(移动返回原始鼠标位,不吸附) |
Ctrl |
临时启用正交(当前点与前一顶点像素 x|y 取差小者对齐,非地理方向) |
Backspace |
删除最后一个点(map.setCustomKeyValue("_disable_drawkey_backspacekey", true) 可禁用——须严格布尔 true,字符串 "true" 不生效) |
ESC |
取消 |
Enter |
结束(顶点不足时 resolve {cancel:true}) |
三、捕捉标记样式
捕捉指示不是 meta 属性——源码里 guide 要素带 properties.isSnapGuide: "true"(捕捉节点 id 为 SNAPNODE_GUIDE,对齐辅助线(guides)id 为 VERTICAL_GUIDE/HORIZONTAL_GUIDE)。内置样式对 isSnapGuide=="true" 的 LineString 画一条红色虚线(guide 图层)。
要自定义捕捉节点点样式,往 opts.styles 追加一个 filter 命中 isSnapGuide 的 Point 图层:
const opts = vjmap.cloneDeep(vjmap.Draw.defaultOptions()); // defaultOptions 是浅拷贝,styles 全局共享,须深拷贝
opts.styles.push({
id: "my-snap-point",
type: "circle",
filter: ["all", ["==", "$type", "Point"], ["==", "isSnapGuide", "true"]],
paint: { "circle-radius": 6, "circle-color": "#ff0000" }
});
const draw = new vjmap.Draw.Tool(opts);
四、捕捉源
1. 捕捉 CAD 图上的点线(栅格模式)
const snapObj = { features: [] };
const res = await svc.conditionQueryFeature({
fields: "s3", condition: "s3 != ''", limit: 100000
});
for (const item of res.result) {
const pts = item.s3.split(";").map(p => p.split(",").map(Number));
const coords = pts.filter(p => p.length >= 2).map(([x, y]) => map.toLngLat([x, y]));
if (coords.length === 1) {
snapObj.features.push({ type: "Feature", geometry: { type: "Point", coordinates: coords[0] } });
} else if (coords.length > 1) {
snapObj.features.push({ type: "Feature", geometry: { type: "LineString", coordinates: coords } });
}
}
2. 捕捉矢量样式内已渲染要素
snapObj.features = map.queryRenderedFeatures({ layers: ["vector-layer-lines"] });
3. 捕捉 Draw 工具里自己绘制的要素
通过 draw.getAll() 取出给下一个绘制:
const snapFeatures = draw.getAll().features;
await vjmap.Draw.actionDrawLineSting(map, { api: { getSnapFeatures: { features: snapFeatures } } });
五、禁用某实体捕捉
draw.setFeatureProperty(featureId, "noSnap", true);
六、正交模式
按住 Ctrl 时,下一个点强制水平 / 垂直相对视口(不是地理方向)。程序内无直接 API,可通过样式或自己判断移动方向。
七、捕捉性能
getSnapFeatures数据量大(>1 万要素)时,绘制每帧都会全量遍历 → 可以只保留视口内 features。- 仅在绘制开始前填
snapObj.features,绘制过程中避免频繁 push。
八、自定义捕捉回调
当前发布版没有 onSnap 回调(运行时与 d.ts 均不存在)——api.getSnapFeatures 是唯一注入点;要"命中即知"可在 updatecoordinate 回调里自行对 snapObj.features 做最近点判定。
九、对齐辅助线(guides,不是网格捕捉)
guides: true 时,鼠标接近某个已有顶点的 x 或 y 时,画一条经过该顶点的竖直 / 水平参考线(内置按钮"捕捉网格"snap_mode_grid 开关的就是它);没有按像素间距的网格捕捉。snapGridPx 只是参考线的半长(像素):
const draw = new vjmap.Draw.Tool({
guides: true,
snapOptions: { snapGridPx: 500 } // 参考线向两侧各延伸 500px
});
十、常见坑
- 绘制速度变慢 → 捕捉要素过多;按视口范围裁剪。
- CAD 文字位置捕不到:因为 s3 字段未包含文字;测量工具可能需额外查询 Text 实体。
- 不同图之间共享 snapObj → 坐标系不同会偏移;每张图独立。
- Alt 释放后捕捉消失:这是临时切换的预期行为。