节点

节点通过 FlowNodeEntity 定义

节点核心 API

  • id: string 节点 id
  • flowNodeType: string | number 节点类型
  • bounds: Rectangle 获取节点的 x,y,width,height, 等价于 transform.bounds
  • blocks: FlowNodeEntity[] 获取子节点 (如 Loop)
  • parent: FlowNodeEntity | undefined 获取父节点
  • document: WorkflowDocument 文档链接
  • transform: FlowNodeTransformData 获取节点的 transform 矩阵数据
  • renderData: FlowNodeRenderData 获取节点的渲染数据, 包含渲染状态等
  • form: NodeFormProps 获取节点的表单数据, 等价于 getNodeForm
  • scope: FlowNodeScope 变量作用域
  • privateScope: FlowNodeScope 变量私有作用域
  • lines: WorkflowNodeLinesData 自由布局线条数据
  • ports: WorkflowNodePortsData 自由布局端口数据
  • getNodeRegistry(): WorkflowNodeRegistry 获取节点注册器
  • getService(): 获取 IOC 服务,如 node.getService(HistoryService)
  • getExtInfo(): 获取节点扩展数据, 如 node.getExtInfo<{ test: string }>()
  • updateExtInfo(): 更新节点扩展数据, 如 node.updateExtInfo<{ test: string }>({ test: 'test' })
  • dispose(): 销毁节点
  • toJSON(): json 序列化

节点数据

通过 node.toJSON() 可以获取

基本结构:
  • id: string 节点唯一标识, 必须保证唯一
  • meta: object 节点的 ui 配置信息,如自由布局的 position 信息放这里
  • type: string | number 节点类型,会和 nodeRegistries 中的 type 对应
  • data: object 节点表单数据, 业务可自定义
  • blocks: array 节点的分支, 采用 block 更贴近 Gramming 自由布局布局场景会用在子画布的子节点
  • edges: array 子画布的边数据
const nodeData: FlowNodeJSON = {
  id: 'xxxx',
  type: 'condition',
  data: {
    title: 'MyCondition',
    desc: 'xxxxx'
  },
}

节点定义

在自由布局场景,节点定义用于声明节点的初始化位置/大小,端口,表单渲染等, 详细见 声明节点

当前渲染节点获取

通过 useNodeRender 获取节点相关方法

function BaseNode() {
  const { id, type, data, updateData, node } = useNodeRender()
}

获取当前节点的输入/输出节点或线条

// 获取当前节点的输入节点(通过连接线计算)
node.lines.inputNodes
// 获取所有输入节点 (会往上递归获取所有)
node.lines.allInputNodes
// 获取输出节点
node.lines.outputNodes
// 获取所有输出节点
node.lines.allOutputNodes
// 输入线条 (包含 isDrawing 或 isHidden 的线条)
node.lines.inputLines
// 输出线条 (包含 isDrawing 或 isHidden 的线条)
node.lines.outputLines
// 所有线条 (不包含 isDrawing 或 isHidden 的线条)
node.lines.availableLines

创建节点

const ctx = useClientContext()

ctx.document.createWorkflowNode({
  id: 'xxx', // 要保证画布内唯一
  type: 'custom',
  meta: {
    /**
     * 如果不传入,则默认在画布中间创建
     * 如果要通过鼠标位置获取 position (如点击画布任意位置创建节点),可通过 `ctx.playground.config.getPosFromMouseEvent(mouseEvent)` 转换
     */
    position: { x: 100, y: 100 } //
  },
  data: {}, // 表单相关数据
  blocks: [], // 子画布的节点
  edges: [] // 子画布的边
})
const dragService = useService<WorkflowDragService>(WorkflowDragService);

// 这里的 mouseEvent 会自动转成 画布的 position
dragService.startDragCard(nodeType, mouseEvent, {
  id: 'xxxx',
  data: {}, // 表单相关数据
  blocks: [], // 子画布的节点
  edges: [] // 子画布的边
})

删除节点

通过 node.dispose 删除节点

function BaseNode({ node }) {
  function onClick() {
    node.dispose()
  }
  return (
    <button onClick={onClick}>Delete</button>
  )
}

更新节点 data 数据

function BaseNode() {
  const { node, form } = useNodeRender();
  // 1. form.values 对应节点的 data 数据
  // 2. form.setValueIn('title', 'xxxx') 修改 data.title
  // 3. form.getValueIn('title') 获取 data.title
  // 4. form.updateFormValues({ ... }) 更新表单所有数据

  function onChange(e) {
    form.setValueIn('title', e.target.value)
  }
  return <input value={form.values.title} onChange={onChange}/>
}

function FormRender() {
  return (
    <Field name="title">
      <Input />
    </Field>
  )
}

更新节点的 extInfo 数据

extInfo 用于存储 一些 ui 状态, 如果未开启节点引擎,节点的 data 数据会默认存到 extInfo 里

function BaseNode({ node }) {
  const times = node.getExtInfo()?.times || 0
  function onClick() {
    node.updateExtInfo({ times: times ++ })
  }
  return (
    <div>
      <span>Click Times: {times}</span>
      <button onClick={onClick}>Click</button>
    </div>
  )
}