React components for building x6 editors
参照lloydzhou/antv-x6-vue实现组件抽象
- 由于x6主要面向编辑场景,所以对每一个节点有更多的交互逻辑。所以,将x6的Shape抽象成组件,每一个组件负责管理自己的生命周期。
- 针对复杂的自定义图形,利用x6支持渲染html组件antv-x6-html2的功能,节点渲染交给当前组件,将图形相关逻辑交给x6。
- 基础示例使用了
antd
的InputNumber
(一个带按钮的输入框)展示了自定义组件如何做到和x6做数据交互
- swimlane 泳道图参照
x6
官方示例实现
- DAG画布参照
x6
官方的DAG示例实现AlgoNode
的节点逻辑与官方示例相比较处理起来更简单
- ER图参照
x6
官方的ER图示例
- 展开收起树形图参照
x6
官方的示例
类 |
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>
);
}