LogicFlow DynamicGroup 连线限制机制:`disallowEdgeConnectToGroup` 严格模式的设计与实现
2026/9/15 10:49:39 网站建设 项目流程

LogicFlow DynamicGroup 连线限制机制:disallowEdgeConnectToGroup严格模式的设计与实现

【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架,支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow

DynamicGroup 是 LogicFlow 内置的分组容器节点。分组作为"容器"的语义,天然不应当被当作普通流程边的端点,但历史版本默认允许手动将边连到/从分组节点本身。本文基于 2026-06-16 连线限制设计文档,完整讲解 LogicFlow 如何以"默认零成本、严格模式可选、节点级可覆盖"的三层策略解决这一语义矛盾,并深入源码验证连接规则求值、锚点控制与折叠虚拟边不受影响这三条实现路径。读完你将掌握disallowEdgeConnectToGroup的配置方式、properties.allowEdgeConnect的覆盖优先级,以及如何通过测试用例验证分组连线限制行为。

背景:分组作为容器,为何不允许被连线

dynamic-group节点继承自RectNodeModel(见 model.ts),展开态下保留 4 个"透明但可交互"的锚点。在默认行为下,用户可以做两件与容器语义相悖的操作:

  • 将外部节点连线到分组节点本身;
  • 从分组节点拖出连线连到普通节点。

这与分组作为容器的语义不一致,也容易与折叠时"虚拟边挂到分组边界"的行为产生混淆。主流竞品(如 draw.io、BPMN Group、React Flow 默认 group)普遍不在展开态把分组当作 Sequence Flow 端点。

但设计文档同时强调升级成本:大量存量项目已经依赖"允许连到分组"的默认行为,因此不能在 minor 版本中静默修改默认值。最终决策是:默认保持允许(与现网一致),提供插件级 opt-in 严格模式

决策要点一览

决策
范围dynamic-group;不改Pool/Lane
默认行为维持允许手动连到/从分组(升级零成本)
严格模式插件级 opt-in:disallowEdgeConnectToGroup: true
节点覆盖properties.allowEdgeConnect可覆盖插件级配置
折叠虚拟边不受影响(仍走addEdge,不经过连接规则校验)
锚点保留 4 个锚点;严格模式下edgeAddable: false
版本Minor 新能力(非 breaking),CHANGELOG 标记为"新增 strict 选项"

行为定义:是否允许手动连分组的求值规则

设计文档给出了明确的优先级规则:

若 properties.allowEdgeConnect 已显式设置(true/false) → 以节点 property 为准 否则 → allow = !plugin.disallowEdgeConnectToGroup

对应真值表:

plugin.disallowEdgeConnectToGroupproperties.allowEdgeConnect手动连到/从分组
false(默认)未设置✅ 允许(现状)
falsefalse❌ 禁止
falsetrue✅ 允许
true未设置❌ 禁止
truetrue✅ 允许
truefalse❌ 禁止

源码中的求值实现

这段求值逻辑在DynamicGroupNodeModel.isManualEdgeConnectAllowed()中原样实现(model.ts):

isManualEdgeConnectAllowed(): boolean { const { allowEdgeConnect } = this.properties ?? {} if (allowEdgeConnect !== undefined) { return allowEdgeConnect } const plugin = this.graphModel.dynamicGroup as | DynamicGroupPluginApi | undefined return !plugin?.disallowEdgeConnectToGroup }

可见:节点级 property 拥有最高优先级;未显式设置时回退到插件选项。插件通过graphModel.dynamicGroup暴露配置,该实例在DynamicGroup.init()中通过graphModel.dynamicGroup = this挂载(见 index.ts)。

不受影响的场景

以下场景明确经过上述规则:

  • 折叠时由createVirtualEdge/graphModel.addEdge创建、指向分组的虚拟边;
  • lf.render()/addEdge载入的、端点已经是分组的历史边(只读展示;若用户手动 adjust 端点至分组,则走上述规则);
  • 组内节点 ↔ 外部节点、组内 ↔ 组内 的连线(本需求不限制)。

实现机制:组合方案(规则 + 锚点)

严格模式的实现采用"双保险"组合:连接规则拦截外部连入锚点edgeAddable禁止从分组拖出

1. 连接规则:getConnectedTargetRules/getConnectedSourceRules

DynamicGroupNodeModel中重写了两个规则方法(model.ts):

getConnectedTargetRules() { const rules = super.getConnectedTargetRules() rules.push({ message: '分组节点不允许作为边的终点', validate: () => this.isManualEdgeConnectAllowed(), }) return rules } getConnectedSourceRules() { const rules = super.getConnectedSourceRules() rules.push({ message: '分组节点不允许作为边的起点', validate: () => this.isManualEdgeConnectAllowed(), }) return rules }

在核心层,这些规则由BaseNodeModel.isAllowConnectedAsTarget/isAllowConnectedAsSource遍历调用:任一规则validate返回false即中断,最终返回{ isAllPass, msg }(见 BaseNodeModel.ts)。因此严格模式下,外部节点连线到分组或从分组拖出连线都会收到分组节点不允许作为边的终点/起点的校验失败消息。

2. 锚点控制:getDefaultAnchor

为禁止从分组拖出连线,严格模式下锚点被标记为不可连出(model.ts):

getDefaultAnchor() { const anchors = super.getDefaultAnchor() if (this.isManualEdgeConnectAllowed()) { return anchors } return anchors.map((anchor) => ({ ...anchor, edgeAddable: false, })) }

锚点本身仍保留(数量不变),只是edgeAddable: false。这与"折叠虚拟边需依赖分组锚点"的设计保持一致——折叠时插件仍会通过分组锚点创建虚拟边,因此文档特别提示:请勿将分组锚点数量设为 0

API:插件选项与节点 property

插件选项

通过pluginsOptions.dynamicGroup传入(键名与DynamicGroup.pluginNamedynamicGroup一致):

const lf = new LogicFlow({ container: document.querySelector('#container'), plugins: [DynamicGroup], pluginsOptions: { dynamicGroup: { disallowEdgeConnectToGroup: true, // 推荐新业务开启;默认 false }, }, })

对应的类型定义(index.ts):

export type DynamicGroupOptions = Partial<{ isCollapsed: boolean /** 为 true 时禁止手动将边连到/从分组节点;默认 false */ disallowEdgeConnectToGroup: boolean /** 删除分组时是否级联删除成员;默认 true */ cascadeDeleteChildren: boolean /** 拖拽节点进入分组时的感应外框样式 */ sensorOutline: SensorOutlineOptions }>

插件构造函数通过assign(this, options)将选项写入实例(见 index.ts),disallowEdgeConnectToGroup默认值为false

节点级 property

单个分组节点可通过properties.allowEdgeConnect覆盖插件级配置:

{ type: 'dynamic-group', x: 300, y: 300, properties: { // 插件已开启 disallowEdgeConnectToGroup 时,仅此分组仍允许手动连线 allowEdgeConnect: true, }, }

该字段已加入IGroupNodeProperties类型(model.ts):

/** * 是否允许手动将边连到/从本分组节点。 * 显式设置时优先于插件选项 disallowEdgeConnectToGroup。 */ allowEdgeConnect?: boolean

测试用例:行为被完整验证

设计文档规划的测试落在 connect-rules.test.ts,测试夹具由 fixtures.ts 提供(通过pluginsOptions.dynamicGroup注入选项、渲染dynamic-group节点与一个circle外部节点):

ID场景断言
C1默认插件(无 options)分组可作为 target/source(isAllowConnectedAsTarget/AsSource(...).isAllPass === true
C2disallowEdgeConnectToGroup: true分组不可作为 target/source(isAllPass === false
C3strict +allowEdgeConnect: true该分组可连
C4非 strict +allowEdgeConnect: false该分组不可连
C5strict 下锚点锚点数量 > 0,且每个锚点edgeAddable === false
C6回归collapse-edge.test.tsE1/E7/E8全部仍绿

折叠相关回归用例E1(折叠 → 删虚拟边 → 展开 → 边不复活)、E7(Gateway 双分支折叠生成两条虚拟边)、E8(折叠 → 拖分组 → 展开 → 边端点仍在锚点上)位于 collapse-edge.test.ts,验证了严格模式不会破坏折叠虚拟边的既有行为。

用户通知与升级策略(非 breaking)

设计文档明确了变更的落地渠道:

渠道内容
packages/extension/CHANGELOG.mdMinor / Feature:新增disallowEdgeConnectToGroup;默认行为不变
dynamic-group.zh.md重写 FAQ:默认允许;推荐新业务开启 strict;节点级 override 示例
update.zh.md可选短段:新业务推荐配置 snippet
dynamic-group-regression增加 strict 场景说明或子示例

明确不做:运行时 console 告警、Major 版本、默认 flip。

CHANGELOG 中已记录该能力(见 packages/extension/CHANGELOG.md):

feat(dynamic-group): 新增插件选项disallowEdgeConnectToGroup(默认false,行为与历史版本一致)。设为true时禁止手动将边连到/从分组节点;节点properties.allowEdgeConnect可覆盖。

自定义分组的扩展路径

若未使用插件选项、需要更细粒度的控制,仍可按核心层 连接规则 的机制,在继承DynamicGroupNodeModel的子类中重写getConnectedTargetRules/getConnectedSourceRules/getDefaultAnchor。例如:

class CustomGroupModel extends dynamicGroup.model { getConnectedTargetRules() { const rules = super.getConnectedTargetRules() // 自定义更严格的规则,如仅允许特定节点类型连入 return rules } }

主要改动文件清单

  • packages/extension/src/dynamic-group/index.ts —disallowEdgeConnectToGroup选项与DynamicGroupOptions类型
  • packages/extension/src/dynamic-group/model.ts — 连接规则、getDefaultAnchorisManualEdgeConnectAllowedallowEdgeConnect属性
  • packages/extension/test/dynamic-group/connect-rules.test.ts — 新增测试
  • packages/extension/test/dynamic-group/collapse-edge.test.ts — 回归用例
  • sites/docs/docs/tutorial/extension/dynamic-group.zh.md — 官方插件文档
  • packages/extension/CHANGELOG.md — 变更记录
  • examples/dynamic-group-regression/README.md — 回归示例说明(可选)

非目标与后续方向

本设计明确排除了以下内容:

  • Pool / Lane 连线策略(不影响泳道语义);
  • Core 层默认规则;
  • 3.0 版本默认 flip 为 strict(可留待后续 major 版本再议)。

验收清单

设计文档给出的最终验收标准如下:

  • 不传插件 options 时行为与改前一致(C1)
  • disallowEdgeConnectToGroup: true禁止手动连分组(C2–C5)
  • 折叠虚拟边回归通过(C6)
  • 文档与 CHANGELOG 已更新
  • DynamicGroupOptions类型导出可用

实践建议:新业务初始化时直接开启disallowEdgeConnectToGroup: true作为默认策略,引导用户连线到组内业务节点而非分组框;存量项目保持默认值即可实现零成本升级;个别需要把分组当端点的场景,用properties.allowEdgeConnect: true按节点放行。这样既保证了容器语义的正确性,又完整保留了历史兼容与灵活性。

【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架,支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询