Awesome
antv-x6-react
React components for building x6 editors
参照lloydzhou/antv-x6-vue实现组件抽象
核心思想
- 由于x6主要面向编辑场景,所以对每一个节点有更多的交互逻辑。所以,将x6的Shape抽象成组件,每一个组件负责管理自己的生命周期。
- 针对复杂的自定义图形,利用x6支持渲染html组件antv-x6-html2的功能,节点渲染交给当前组件,将图形相关逻辑交给x6。
Online Demos
- 基础示例使用了
antd
的InputNumber
(一个带按钮的输入框)展示了自定义组件如何做到和x6做数据交互
- swimlane 泳道图参照
x6
官方示例实现
- DAG画布参照
x6
官方的DAG示例实现AlgoNode
的节点逻辑与官方示例相比较处理起来更简单
- ER图参照
x6
官方的ER图示例
- 展开收起树形图参照
x6
官方的示例
安装
yarn add antv-x6-react
Components
类 | shape 名称 | 描述 |
---|
Node | rect | 等同于Shape.Rect |
Edge | edge | 等同于Shape.Edge |
Shape.Rect | rect | 矩形。 |
Shape.Circle | circle | 圆形。 |
Shape.Ellipse | ellipse | 椭圆。 |
Shape.Polygon | polygon | 多边形。 |
Shape.Polyline | polyline | 折线。 |
Shape.Path | path | 路径。 |
Shape.Image | image | 图片。 |
Shape.HTML | html | HTML 节点,使用 foreignObject 渲染 HTML 片段。 |
Shape.TextBlock | text-block | 文本节点,使用 foreignObject 渲染文本。 |
Shape.BorderedImage | image-bordered | 带边框的图片。 |
Shape.EmbeddedImage | image-embedded | 内嵌入矩形的图片。 |
Shape.InscribedImage | image-inscribed | 内嵌入椭圆的图片。 |
Shape.Cylinder | cylinder | 圆柱。 |
Shape.Edge | edge | 边。 |
Shape.DoubleEdge | double-edge | 双线边。 |
Shape.ShadowEdge | shadow-edge | 阴影边。 |
另外提供帮助函数
名称 | 描述 |
---|
useCell | 使用这个函数可以通过传递markup之类的参数自定义节点 |
useCellEvent | 通过这个函数绑定事件到cell上面 |
useNodeSize | 通过这个函数可以按照react节点内部渲染的大小调整节点大小 |
名称 | 描述 |
---|
Grid | 渲染网格 |
Background | 渲染背景 |
Scroller | 滚动组件 |
Clipboard | 剪贴板,配合Keyboard 组件可以使用ctrl+c /ctrl+x /ctrl+v |
Keyboard | 键盘快捷键 |
MouseWheel | 鼠标滚轮,支持使用滚轮实现画布放大缩小 |
Connecting | 配置连线相关参数和帮助方法 |
名称 | 描述 |
---|
Snapline | 对齐线 |
Selection | 点选/框选 |
MiniMap | 小地图 |
Contextmenu | 右键菜单 |
import Graph, { Grid, Background, Clipboard, Keyboard, MouseWheel, Connecting } from './lib'
import { Node, Edge, ReactNode } from './lib'
import { Selection, MiniMap, ContextMenu, Portal } from './lib'
function Node1(props: any) {
// 自动按照内部节点大小更新x6节点大小
useNodeSize(props)
const { node, data = {} } = props;
const { num = 0 } = data;
return (
<div style={{width: 150, border: '1px solid'}}>
<Button onClick={(e) => node.setData({ num: num + 1 })}>
Ant Button {num}
</Button>
<InputNumber value={num} onChange={num => node.setData({ num })} />
</div>
);
}
function App() {
return (
<div className="App">
{/* 内部会自动判断,只要这个组件被挂载了就使用portal模式,否则使用ReactDOM.render */}
<PortalProvider />
<Graph>
<Grid />
<Background />
<Clipboard />
<Keyboard />
<MouseWheel />
<Selection />
<Connecting />
<Node id="1" x="100" y="100" label="node1" />
<Node id="2" x="200" y="200" label="node2" />
<ReactNode id="999" x="650" y="200" data={{num: 2}} component={Node1} />
<ReactNode id="99" x="500" y="200" data={{num: 2}} component={Node1} />
<ReactNode id="9" x="500" y="300" data={{num: 2}} component={Node1} primer="circle" />
<Edge source="1" target="2" />
<ContextMenu>
<Menu style={{background: '#fff'}}>
<Menu.Item>菜单1</Menu.Item>
<Menu.Item>菜单2</Menu.Item>
<Menu.Item>菜单3</Menu.Item>
</Menu>
</ContextMenu>
</Graph>
</div>
);
}