G6 提供了自定义边的机制,方便更加定制化的边,包括含有复杂图形的边、复杂交互的边、带有动画的边等。
可以通过 G6.registerEdge(typeName: string, edgeDefinition: object, extendedEdgeType?: string) 注册一个新的边类型,其中:
- typeName:该新边类型名称;
- extendedEdgeType:被继承的边类型,可以是内置边类型名,也可以是其他自定义边的类型名。extendedEdgeType 未指定时代表不继承其他类型的边;
- edgeDefinition:该新边类型的定义,其中必要函数详见 自定义机制 API。当有 extendedEdgeType 时,没被复写的函数将会继承 extendedEdgeType 的定义。
需要注意的是,自定义边/节点时,若给定了 extendedEdgeType,如 draw,update,setState 等必要的函数若不在 edgeDefinition 中进行复写,将会继承 extendedEdgeType 中的相关定义。
定义边
实现垂直的折线:
自定义边
js
G6.registerEdge('hvh', {
draw(cfg, group) {
const startPoint = cfg.startPoint;
const endPoint = cfg.endPoint;
const shape = group.addShape('path', {
attrs: {
stroke: '#333',
path: [
['M', startPoint.x, startPoint.y],
['L', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y], // 三分之一处
['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y], // 三分之二处
['L', endPoint.x, endPoint.y],
],
},
// 在 G6 3.3 及之后的版本中,必须指定 name,可以是任意字符串,但需要在同一个自定义元素类型中保持唯一性
name: 'path-shape',
});
return shape;
},
});
- 上面自定义边中的 startPoint 和 endPoint 分别是是边两端与起始节点和结束节点的交点;
- 可以通过修改节点的锚点(边连入点)来改变 startPoint 和 endPoint 的位置。
在数据中修改 anchorPoints
通过以下的数据,使用自定义的 hvh 边,就可以实现上图最右边的效果。
js
const data = {
nodes: [
{
id: 'node1',
x: 100,
y: 200,
anchorPoints: [
[0, 0.5],
[1, 0.5],
],
},
{
id: 'node2',
x: 200,
y: 100,
anchorPoints: [
[0, 0.5],
[1, 0.5],
],
},
{
id: 'node3',
x: 200,
y: 300,
anchorPoints: [
[0, 0.5],
[1, 0.5],
],
},
],
edges: [
{
id: 'edge1',
target: 'node2',
source: 'node1',
type: 'hvh',
},
{
id: 'edge2',
target: 'node3',
source: 'node1',
type: 'hvh',
},
],
};
扩展现有边
通过 afterDraw 接口给现有的曲线增加动画。
js
G6.registerEdge(
'line-growth',
{
afterDraw(cfg, group) {
const shape = group.get('children')[0];
const length = shape.getTotalLength();
shape.animate(
(ratio) => {
const startLen = ratio * length;
const cfg = {
lineDash: [startLen, length - startLen],
};
return cfg;
},
{
repeat: true,
duration: 2000,
},
);
},
},
'cubic',
);
增加额外图形
通过实现 afterDraw 增加额外图形,为找到边的主要图形 path 上的某个点,可以使用 shape.getPoint(ratio) 获得。
js
G6.registerEdge(
'mid-point-edge',
{
afterDraw(cfg, group) {
// 获取图形组中的第一个图形,在这里就是边的路径图形
const shape = group.get('children')[0];
// 获取路径图形的中点坐标
const midPoint = shape.getPoint(0.5);
// 在中点增加一个矩形,注意矩形的原点在其左上角
group.addShape('rect', {
attrs: {
width: 10,
height: 10,
fill: '#f00',
// x 和 y 分别减去 width / 2 与 height / 2,使矩形中心在 midPoint 上
x: midPoint.x - 5,
y: midPoint.y - 5,
},
name: 'mid-point-edge-rect', // 在 G6 3.3 及之后的版本中,必须指定 name,可以是任意字符串,但需要在同一个自定义元素类型中保持唯一性
});
},
update: undefined,
},
'cubic',
);
边的交互样式
以点击选中、鼠标 hover 到边为示例,实现如下效果:
边过细时点击很难被击中,可以设置 lineAppendWidth 来提升击中范围。
js
// 基于 line 扩展出新的边
G6.registerEdge(
'custom-edge',
{
// 响应状态变化
setState(name, value, item) {
const group = item.getContainer();
const shape = group.get('children')[0]; // 顺序根据 draw 时确定
if (name === 'active') {
if (value) {
shape.attr('stroke', 'red');
} else {
shape.attr('stroke', '#333');
}
}
if (name === 'selected') {
if (value) {
shape.attr('lineWidth', 3);
} else {
shape.attr('lineWidth', 2);
}
}
},
},
'line',
);
// 点击时选中,再点击时取消
graph.on('edge:click', (ev) => {
const edge = ev.item;
graph.setItemState(edge, 'selected', !edge.hasState('selected')); // 切换选中
});
graph.on('edge:mouseenter', (ev) => {
const edge = ev.item;
graph.setItemState(edge, 'active', true);
});
graph.on('edge:mouseleave', (ev) => {
const edge = ev.item;
graph.setItemState(edge, 'active', false);
});