JointJS 如何兼顾 Manhattan 自动布线与 CAD 式线段拖动?
可以先用 Manhattan router 计算正交路径,把中间折点保存为 vertices,再切换到 normal router 并启用 Segments。如果拖动线段时仍需避障,同时保留用户指定的走线,则需要自定义编辑逻辑和路由约束。
相邻 ports 出现多余拐弯时,需要结合端口位置、进出方向、障碍物和搜索网格排查。仅设置 padding: 0 无法保证得到最少拐弯的路径。
为什么不能直接启用 Segments?
JointJS 的 Segments 工具明确只支持 normal router;配合 manhattan 或 orthogonal 使用时,会触发 Segments: incompatible router in use。Segments 官方说明
这里有两种几何数据:模型中的 vertices,以及 router 根据这些点生成的实际路径折点。自动生成的线段未必直接对应模型中的相邻顶点,因此绕过兼容性检查也无法解决编辑对象与实际路径之间的对应关系。
如何实现自动布线后拖动线段?
可以在应用中设置自动和手动两种编辑状态:
- 自动状态使用 Manhattan router 生成初始走线。
- 进入手动状态时,取得当前路由结果中的全部中间折点,复制为普通坐标对象。
- 显式切换到
normalrouter,将这些点写入vertices,然后添加Segments工具。 - 手动调整后保存顶点;只有用户主动选择重新布线时,才重新计算整条路径。
需要保存的是 router 生成的折点。直接读取 link.vertices() 再切换 router,可能丢失自动生成的拐弯。normal router 会直接使用传入的顶点,不再自动补充正交折点。路由器官方说明
下面的代码用于切换 router 并启用工具。routedVertices 必须由应用的路由适配层提供,内容是当前路径的中间折点,不包含 source 和 target 端点;它不是 JointJS 自动提供的变量。
import { dia, linkTools } from '@joint/core';
function enableManualEditing(linkView, routedVertices) {
const vertices = routedVertices.map(({ x, y }) => ({ x, y }));
linkView.removeTools();
linkView.model.set({
router: { name: 'normal' },
vertices
});
linkView.addTools(new dia.ToolsView({
tools: [
new linkTools.Segments({
redundancyRemoval: true
})
]
}));
}
取得路由折点的方法需要按实际 JointJS 版本实现,例如在应用包装的 router 中记录返回的路由点。异步渲染时,应确保取得的是最新计算结果。工具挂载方式可参考 LinkView 官方文档。
进入手动状态后,normal router 不负责避障。元件移动后,应用需要修复首尾连接段,才能继续保持正交;端口的 anchor、connectionPoint 和工具对端点的调整行为也应一并验证。
相邻 ports 出现多余拐弯,应该检查什么?
原问题没有提供端口坐标、元件边界、完整路由配置或 JointJS 版本,因此无法确定具体原因。可以依次检查以下几项:
- 检查端口位置和方向:确认实际连接点位于预期位置,并根据端口朝向配置
startDirections、endDirections。方向限制与布局不匹配时,可能迫使路径绕行。 - 检查搜索步长:
step决定 Manhattan 搜索网格的大小。较小的值可以作为密集布局的对照实验,但会增加计算量;文档建议与 Paper 的gridSize配合使用。 - 检查元件边界:
padding: 0只取消额外留白,source、target 和其他元件仍可能是障碍物。可临时使用excludeEnds辅助定位,正式方案仍需检查路径是否穿过元件。 - 检查是否发生路由回退:搜索超过
maximumLoops时会使用 fallback。默认 fallback 是不负责避障的orthogonalrouter;只有确认搜索预算不足时,才有理由提高该值。
这些参数的含义和限制见 Manhattan router 官方文档。
例如,仅在 source port 位于元件右侧、target port 位于元件左侧时,可以尝试以下方向约束:
link.router('manhattan', {
step: 5,
padding: 0,
startDirections: ['right'],
endDirections: ['left']
});
这里的 5 是实验值,需要结合坐标尺度和性能调整;该配置也不能保证减少拐弯。endDirections: ['left'] 表示从目标元件左侧接入。若端口布局不同,应相应修改或移除限制。
此外,maxAllowedDirectionChange 控制单次方向变化的角度,并不是整条路径的最大拐弯次数。
什么时候需要自定义 router?
如果用户只需要先自动生成走线,再手动整理,先实现状态切换通常更容易控制。
如果用户要求拖动某一段时,该段保持指定位置、其他线段继续避障,就需要额外表达哪些位置必须保留。可以让自定义线段工具将拖动结果转换为必须经过的点,再调用 Manhattan router 计算其余部分。但经过两个点并不保证它们之间始终是一条固定线段,重新寻路仍可能插入拐弯。
对于严格的线段锁定,需要将锁定段作为固定几何,只路由两侧的自由部分,并处理无可行路径时的反馈。可先尝试复用 Manhattan 的避障能力;只有当现有路由无法满足这些约束时,再扩展或替换路由算法。
如果还希望相邻端口优先使用直线或单拐弯连接,可以增加应用层候选路径检查:先验证简短正交路径是否满足端口方向和避障要求,通过后采用,否则交给 Manhattan。这里需要检查完整线段与障碍物的关系,不能只检查拐点是否落在障碍物外。
备注:内容仅供参考。
