怎样在G6里面定义一个自定义节点一直都是一个头疼的问题,我们也在努力让大家能更简单的定义节点,去年我们推出了类jsx定义节点的方案,很感谢大家使用并给出的反馈,这一次我们决定暂时放下与框架无关的限制,通过许多开发者都熟悉的React来帮助大家更好的定义一个节点。向你介绍@antv/g6-react-node,让你开发自定义节点像是开发react组件一样简单。我们支持了类似于Flex布局的自动布局,并且对事件定义精细到了shape级别,只要你会使用react,就会写G6的自定义节点。并且支持图形元素的组件级复用,让你开发图元素更加便捷。
安装
npm install --save @antv/g6-react-node
# or
yarn add @antv/g6-react-node
推荐配合G6 4+使用,但是本插件也兼容G6 3.x版本。
用React定义节点
一、 定义节点keyshape,添加阴影
所有的React定义节点,我们都推荐用一个Group作为根节点来包裹。首先我们定义来这个节点的主要图形(keyshape)。
<Group>
<Rect
style={{
radius: [8],
fill: '#fff',
shadowColor: '#ddd',
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2,
}}
keyshape
draggable
/>
</Group>
二、 利用G的渐变方法给节点加一个标题区
我们在上一步的基础上,再次定义一个带渐变的header。这里内容涉及到了flex布局的小知识,用direction来让元素改变排列的方式,使用flex属性的空元素来让两边可以更好左对齐和右对齐。
<Group>
<Rect
style={{
radius: [8],
fill: '#fff',
shadowColor: '#ddd',
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2,
}}
keyshape
draggable
>
<Rect
style={{
minWidth: 200,
fill: 'l(0) 0:#0049FF 1:#0EB7FF', //使用G的渐变定义fill
radius: [8, 8, 0, 0],
padding: 12,
flexDirection: 'row',//内部元素水平排列
cursor: 'pointer',
alignContent: 'center',
}}
>
<Text style={{ fill: '#fff' }}>数据输入节点 - 日志源</Text>
<Group style={{ flex: 1 }} /> // 通过flex 1的空Group来实现两个元素两端对齐
<Circle
style={{
r: 5,
fill: '#00CF10',
}}
/>
</Rect>
</Rect>
</Group>
三、 在余下区域给节点取值来进行详细信息的补充
需要对不同节点的信息进行透出,那么你可以使用cfg,cfg是这个节点本身的model数据,你可以通过它来展示信息,甚至是控制渲染细节。
const Card = ({ cfg }) => {
return (
<Group>
<Rect
style={{
radius: [8],
fill: '#fff',
shadowColor: '#ddd',
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2,
}}
keyshape
draggable
>
<Rect
style={{
minWidth: 200,
fill: 'l(0) 0:#0049FF 1:#0EB7FF',
radius: [8, 8, 0, 0],
padding: 12,
flexDirection: 'row',
cursor: 'pointer',
alignContent: 'center',
}}
>
<Text style={{ fill: '#fff' }}>数据输入节点 - 日志源</Text>
<Group style={{ flex: 1 }} />
<Circle
style={{
r: 5,
fill: '#00CF10',
}}
/>
</Rect>
<Group style={{ flexDirection: 'row', margin: [6, 12] }}>
<Text style={{ fill: '#222', fontWeight: 'bold' }}>节点ID</Text>
<Text style={{ fill: '#000', margin: [0, 4] }}>{cfg?.id}</Text>
</Group>
<Group style={{ flexDirection: 'row', margin: [6, 12] }}>
<Text style={{ fill: '#222', fontWeight: 'bold' }}>日志来源</Text>
<Text style={{ fill: '#000', margin: [0, 4] }}>点击埋点数据源</Text>
</Group>
</Rect>
</Group>
);
};
四、 定义组件让开发更加顺畅
我们支持来大部分组件的嵌套逻辑,这样就可以将一些相同的视觉元素绑定到一起,可以大幅度减少重复开发。在这里我们定义了一个Button组件来定义按钮组件。
const Button = ({ color = '#2D5AF6', children, onClick }) => (
<Rect
onClick={onClick}
style={{
padding: [4, 8],
fill: color,
margin: [0, 4],
radius: 4,
cursor: 'pointer',
}}
>
<Text style={{ fill: '#fff', cursor: 'pointer' }} onClick={onClick}>
{children}
</Text>
</Rect>
);
const Card = ({ cfg }) => {
return (
<Group>
<Rect
style={{
radius: [8],
fill: '#fff',
shadowColor: '#ddd',
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2,
}}
keyshape
draggable
>
<Rect
style={{
minWidth: 200,
fill: 'l(0) 0:#0049FF 1:#0EB7FF',
radius: [8, 8, 0, 0],
padding: 12,
flexDirection: 'row',
cursor: 'pointer',
alignContent: 'center',
}}
>
<Text style={{ fill: '#fff' }}>数据输入节点 - 日志源</Text>
<Group style={{ flex: 1 }} />
<Circle
style={{
r: 5,
fill: '#00CF10',
}}
/>
</Rect>
<Group style={{ flexDirection: 'row', margin: [6, 12] }}>
<Text style={{ fill: '#222', fontWeight: 'bold' }}>节点ID</Text>
<Text style={{ fill: '#000', margin: [0, 4] }}>{cfg?.id}</Text>
</Group>
<Group style={{ flexDirection: 'row', margin: [6, 12] }}>
<Text style={{ fill: '#222', fontWeight: 'bold' }}>日志来源</Text>
<Text style={{ fill: '#000', margin: [0, 4] }}>点击埋点数据源</Text>
</Group>
<Group style={{ flexDirection: 'row', margin: [6, 12] }}>
<Button>详情</Button>
<Button color="#FF1313">停止</Button>
</Group>
</Rect>
</Group>
);
};
五、组件上的事件绑定
我们将G6大部分事件进行了独立封装,可以基于shape来定义事件的触发,方便更直观的管理事件。
<Group style={{ flexDirection: 'row', margin: [6, 12] }}>
<Button
onClick={() => {
alert(`你点击了${cfg.id}的详情`);
}}
>
详情
</Button>
<Button
onClick={() => {
alert(`你点击了${cfg.id}的停止`);
}}
color="#FF1313"
>
停止
</Button>
</Group>
在G6中使用React定义的节点
当你已经使用React定义了一个节点后,我们就可以使用G6来注册这个自定义节点了
import React from 'react';
import G6 from '@antv/g6';
import {
Rect,
Text,
Circle,
Image,
Group,
createNodeFromReact,
appenAutoShapeListener,
} from '@antv/g6-react-node';
const Button = ({ color = '#2D5AF6', children, onClick }) => (
<Rect
onClick={onClick}
style={{
padding: [4, 8],
fill: color,
margin: [0, 4],
radius: 4,
cursor: 'pointer',
}}
>
<Text style={{ fill: '#fff', cursor: 'pointer' }} onClick={onClick}>
{children}
</Text>
</Rect>
);
const Card = ({ cfg }) => {
return (
<Group>
<Rect
style={{
radius: [8],
fill: '#fff',
shadowColor: '#ddd',
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2,
}}
keyshape
draggable
>
<Rect
style={{
minWidth: 200,
fill: 'l(0) 0:#0049FF 1:#0EB7FF',
radius: [8, 8, 0, 0],
padding: 12,
flexDirection: 'row',
cursor: 'pointer',
alignContent: 'center',
}}
>
<Text style={{ fill: '#fff' }}>数据输入节点 - 日志源</Text>
<Group style={{ flex: 1 }} />
<Circle
style={{
r: 5,
fill: '#00CF10',
}}
/>
</Rect>
<Group style={{ flexDirection: 'row', margin: [6, 12] }}>
<Text style={{ fill: '#222', fontWeight: 'bold' }}>节点ID</Text>
<Text style={{ fill: '#000', margin: [0, 4] }}>{cfg.id}</Text>
</Group>
<Group style={{ flexDirection: 'row', margin: [6, 12] }}>
<Text style={{ fill: '#222', fontWeight: 'bold' }}>日志来源</Text>
<Text style={{ fill: '#000', margin: [0, 4] }}>点击埋点数据源</Text>
</Group>
<Group style={{ flexDirection: 'row', margin: [6, 12] }}>
<Button
onClick={() => {
alert(`你点击了${cfg.id}的详情`);
}}
>
详情
</Button>
<Button
onClick={() => {
alert(`你点击了${cfg.id}的停止`);
}}
color="#FF1313"
>
停止
</Button>
</Group>
</Rect>
</Group>
);
};
G6.registerNode('test', createNodeFromReact(Card));
// 当你创建好Graph后,如果需要使用在节点内定义的事件
appenAutoShapeListener(graph)