唯杰地图 logo唯杰地图
VJMAP
EN

snap-ortho

vjmap/references/interaction/snap-ortho.md 5.2 KB126 行
原文

本文回答:绘图捕捉 / 正交 / 对齐辅助线(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
});

十、常见坑

  1. 绘制速度变慢 → 捕捉要素过多;按视口范围裁剪。
  2. CAD 文字位置捕不到:因为 s3 字段未包含文字;测量工具可能需额外查询 Text 实体。
  3. 不同图之间共享 snapObj → 坐标系不同会偏移;每张图独立。
  4. Alt 释放后捕捉消失:这是临时切换的预期行为。