docs: api custom-service, custom-plugin

This commit is contained in:
xiamidaxia 2025-02-26 15:32:46 +08:00
parent a6ed79b1a3
commit 4845a51ef5
8 changed files with 239 additions and 2 deletions

View File

@ -56,11 +56,12 @@ const nodeRegistry = node.getNodeRegistry<FlowNodeRegistry>()
### getData
等价于 [ECS](/flowgram.ai/guide/concepts/ECS.html) 架构 里获取 Entity 的 Component,目前内置两个核心 Component
等价于 [ECS](/flowgram.ai/guide/concepts/ECS.html) 架构 里获取 Entity 的 Component
```ts pure
node.getData(FlowNodeTransformData) // transform 矩阵数据, 包含节点的 xywidthheight 等信息
node.getData(FlowNodeRenderData) // 节点的渲染数据, 包含渲染状态等数据
node.getData(WorkflowNodeLinesData) // 自由布局的线条数据
```

View File

@ -20,6 +20,14 @@ const allLines = ctx.document.linesManager.getAllLines()
```
## createLine
创建线条
```ts pure
// from和 to 为对应要连线的节点id fromPort, toPort 为 端口 id, 如果节点为单个端口可以不指定
const line = ctx.document.linesManager.createLine({ from, to, fromPort, toPort })
```
## toJSON
导出线条数据
@ -27,3 +35,23 @@ const allLines = ctx.document.linesManager.getAllLines()
```ts pure
const json = ctx.document.linesManager.toJSON()
```
## onAvailableLinesChange
监听所有线条的连线变化
```ts pure
import { useEffect } from 'react'
import { useClientContext, useRefresh } from '@flowgram.ai/free-layout-editor'
function SomeReact() {
const refresh = useRefresh()
const linesManager = useClientContext().document.linesManager
useEffect(() => {
const dispose = linesManager.onAvailableLinesChange(() => refresh())
return () => dispose.dispose()
}, [])
console.log(ctx.document.linesManager.getAllLines())
}
```

View File

@ -9,6 +9,13 @@
```ts pure
import { useClientContext } from '@flowgram.ai/fixed-layout-editor'
const ctx = useClientContext()
console.log(ctx.operation) // FlowOperationService 操作服务
console.log(ctx.document) // FlowDocument 数据文档
console.log(ctx.playground) // Playground 画布
console.log(ctx.history) // HistoryService 历史记录
console.log(ctx.clipboard) // ClipboardService 剪贴板
console.log(ctx.container) // Inversify IOC 容器
console.log(ctx.get(MyService)) // 获取任意的 IOC 模块,详细见 自定义 Service
```
## 自由布局
@ -18,4 +25,11 @@ const ctx = useClientContext()
```ts pure
import { useClientContext } from '@flowgram.ai/free-layout-editor'
const ctx = useClientContext()
console.log(ctx.document) // WorkflowDocument 数据文档
console.log(ctx.playground) // Playground 画布
console.log(ctx.history) // HistoryService 历史记录
console.log(ctx.selection) // SelectionService 选择器服务
console.log(ctx.clipboard) // ClipboardService 剪贴板
console.log(ctx.container) // Inversify IOC 容器
console.log(ctx.get(MyService)) // 获取任意的 IOC 模块,详细见 自定义 Service
```

View File

@ -24,10 +24,13 @@ const playground3 = useClientContext().get<Playground>(Playground)
/**
* inversify: https://github.com/inversify/InversifyJS
*/
import { injectable } from 'inversify'
import { injectable, inject } from 'inversify'
import { FlowDocument } from '@flowgram.ai/fixed-layout-editor'
@injectable()
class MyService {
// 依赖注入单例模块
@inject(FlowDocument) flowDocument: FlowDocument
// ...
}

View File

@ -2,6 +2,9 @@
"form",
"variable",
"history",
"lines",
"custom-service",
"custom-plugin",
{
"type": "dir",
"name": "interactive",

View File

@ -0,0 +1,90 @@
# 自定义插件
## 插件的生命周期说明
```tsx pure
/**
* from: https://github.com/coze-dev/flowgram.ai/blob/main/packages/canvas-engine/core/src/plugin/plugin.ts
*/
import { ContainerModule, interfaces } from 'inversify';
export interface PluginBindConfig {
bind: interfaces.Bind;
unbind: interfaces.Unbind;
isBound: interfaces.IsBound;
rebind: interfaces.Rebind;
}
export interface PluginConfig<Opts, CTX extends PluginContext = PluginContext> {
/**
* 插件 IOC 注册, 等价于 containerModule
* @param ctx
*/
onBind?: (bindConfig: PluginBindConfig, opts: Opts) => void;
/**
* 画布注册阶段
*/
onInit?: (ctx: CTX, opts: Opts) => void;
/**
* 画布准备阶段,一般用于 dom 事件注册等
*/
onReady?: (ctx: CTX, opts: Opts) => void;
/**
* 画布销毁阶段
*/
onDispose?: (ctx: CTX, opts: Opts) => void;
/**
* 画布所有 layer 渲染结束
*/
onAllLayersRendered?: (ctx: CTX, opts: Opts) => void;
/**
* IOC 模块,用于更底层的插件扩展
*/
containerModules?: interfaces.ContainerModule[];
}
```
## 创建插件
```tsx pure
/**
* 如果希望插件固定布局和自由布局都能使用, 请只用
* import { definePluginCreator } from '@flowgram.ai/core'
*/
import { definePluginCreator, FixedLayoutPluginContext } from '@flowgram.ai/fixed-layout-editor'
export interface MyPluginOptions {
opt1: string;
}
export const createMyPlugin = definePluginCreator<MyPluginOptions, FixedLayoutPluginContext>({
onBind: (bindConfig, opts) => {
// 注册 IOC 模块, Service 如何定义 见 自定义 Service
bindConfig.bind(MyService).toSelf().inSingletonScope()
},
onInit: (ctx, opts) => {
// 插件配置
console.log(opts.opt1)
// ctx 对应 FixedLayoutPluginContext 或者 FreeLayoutPluginContext
console.log(ctx.document)
console.log(ctx.playground)
console.log(ctx.get<MyService>(MyService)) // 获取 IOC 模块
},
});
```
## 添加插件
```tsx pure title="use-editor-props.ts"
// EditorProps
{
plugins: () => [
createMyPlugin({
opt1: 'xxx'
})
]
}
```

View File

@ -0,0 +1,40 @@
# 自定义 Service
业务中需要抽象出单例服务便于插件化管理
```tsx pure
/**
* inversify: https://github.com/inversify/InversifyJS
*/
import { injectable, inject } from 'inversify'
import { useMemo } from 'react';
import { FlowDocument, type FixedLayoutProps } from '@flowgram.ai/fixed-layout-editor'
@injectable()
class MyService {
// 依赖注入单例模块
@inject(FlowDocument) flowDocument: FlowDocument
// ...
}
function BaseNode() {
const mySerivce = useService<MyService>(MyService)
}
export function useEditorProps(
): FixedLayoutProps {
return useMemo<FixedLayoutProps>(
() => ({
// ....other props
onBind: ({ bind }) => {
bind(MyService).toSelf().inSingletonScope()
},
materials: {
renderDefaultNode: BaseNode
}
}),
[],
);
}
```

View File

@ -0,0 +1,58 @@
# 自由布局线条
自由布局的线条通过 [WorkflowLinesManager](/flowgram.ai/api/core/workflow-lines-manager.html) 管理
## 获取当前节点的输入/输出节点
```ts pure
import { WorkflowNodeLinesData } from '@flowgram.ai/free-layout-editor'
// 获取当前节点的输入节点(通过连接线计算)
node.geData(WorkflowNodeLinesData).inputNodes
// 获取所有输入节点 (会往上递归获取所有)
node.geData(WorkflowNodeLinesData).allInputNodes
// 获取输出节点
node.geData(WorkflowNodeLinesData).outputNodes
// 获取所有输出节点
node.geData(WorkflowNodeLinesData).allOutputNodes
```
## 节点监听自身的连线变化并刷新
```tsx pure
import {
useRefresh,
WorkflowNodeLinesData,
} from '@flowgram.ai/free-layout-editor';
function NodeRender({ node }) {
const refresh = useRefresh()
const linesData = node.get(WorkflowNodeLinesData)
useEffect(() => {
const dispose = linesData.onDataChange(() => refresh())
return () => dispose.dispose()
}, [])
return <div>xxxx</div>
}
```
## 监听所有线条的连线变化
```ts pure
import { useEffect } from 'react'
import { useClientContext, useRefresh } from '@flowgram.ai/free-layout-editor'
function SomeReact() {
const refresh = useRefresh()
const linesManager = useClientContext().document.linesManager
useEffect(() => {
const dispose = linesManager.onAvailableLinesChange(() => refresh())
return () => dispose.dispose()
}, [])
console.log(ctx.document.linesManager.getAllLines())
}
```