Graphin的特殊之处
首先我们随便按照官方文档复制一份代码出来跑一跑。
我们渲染好一个画板在页面后,打开检查,会发现一个有趣的现象:所有组件全部被隐式集成在仅仅一个标签:< canvas > 里面了,这和我们之前经常见到的neo4j等图分析画板并不一样
其实这种方式新手上手还是比较容易的,几行代码就可以实现一个惟妙惟肖的图出来。
自定义交互的目标
那么问题来了,所有点、边全部都在canvas里,也就是说我们没有办法直接获得任何node或edge的实例标签,那怎么针对每个独特的边和点执行特定操作呢?
对Grphin实现逻辑的理解
在官方文档里,我们可以发现所谓的ToolBar、ToolTip,以及各种自定义的右键ContextBar,其实都有着一种十分相似且统一的编码方式:自定义组件,将组件引入Grphin,canvas内部自动渲染这些组件所带有的“逻辑”
ToolBar这种东西是阿里已经封装好的组件了,那当我们希望自定义一些组件时,在return函数之前就应当定义好整个组件的内容,随后再加入Graphin内部。
例子:单击特定节点触发特定函数——聚焦&&显示节点信息
那么,在这里,我加入了一个自定义的ClickBehavior,即点击后触发的事件 该组件作为一个函数,我们会发现它只是作为一个“函数逻辑”被加入到canvas当中,不return不render任何标签,也就是说这一函数逻辑被编写后被Graphin采用了 Graphin是如何知道自己要不要采用一个自定义交互(Behavior)的呢?
- 第一种方法就是通过注册交互,这一种适合实现简单的自定义交互,例如官方文档中的案例
import React from 'react';
import Graphin, { IG6GraphEvent, Utils, GraphinData } from '@antv/graphin';
import { message } from 'antd';
import { INode, NodeConfig } from '@antv/g6';
const data: GraphinData = Utils.mock(8).circle().graphin();
Graphin.registerBehavior('sampleBehavior', {
getEvents() {
return {
'node:click': 'onClick',
};
},
onClick(evt: IG6GraphEvent) {
const node = evt.item as INode;
const model = node.getModel() as NodeConfig;
message.info(model.id);
// TODO
},
});
/**
* @example
* https://g6.antv.vision/zh/docs/api/Behavior
*/
export default () => {
return <Graphin data={data} layout={{ type: 'concentric' }} modes={{ default: ['sampleBehavior'] }} />;
};
并在graphin组件
2. 第二种方法就是像下文一样利用useContext(GraphinContext)
解决Graphin和ClickBehavior之间的组件传值
Child.js
我自定义了一些点和边,并为点和边建立了点击事件
import React, { useEffect, useContext, useState } from 'react';
import Graphin, { GraphinContext, Behaviors } from '@antv/graphin';
import { Toolbar } from '@antv/graphin-components';
const layout = {
type: 'graphin-force',
};
const { DragNodeWithForce } = Behaviors;
const ClickBehavior = () => {
// 解决canvas和click组件传参问题
const { graph, apis } = useContext(GraphinContext);
useEffect(() => {
// 初始化聚焦到0
apis.focusNodeById('node0');
const nodeClick = (evt) => {
const node = evt.item;
const model = node.getModel();
apis.focusNodeById(model.id);
console.log(model.id)
};
const edgeClick = (evt) =>{
const edge = evt.item;
const model = edge.getModel();
console.log(model.id)
}
// 每次点击聚焦到点击节点上
graph.on('node:click', nodeClick);
graph.on('edge:click', edgeClick);
}, []);
// 不会渲染任何东西在canvas上,只把交互逻辑告知canvas
return null;
};
const Child = () => {
const [autoPin, setAutoPin] = useState(false);
const onChange = checked => {
setAutoPin(checked);
};
const data = {
combos: undefined,
edges:[
{id: 'edge0', source:"node0", target:"node1"},
{id: 'edge1', source:"node0", target:"node2"},
{id: 'edge2', source:"node0", target:"node3"},
{id: 'edge3', source:"node0", target:"node4"},
{id: 'edge4', source:"node0", target:"node5"},
],
nodes:[
{id: 'node0', label: 'node0', type: 'graphin-circle'},
{id: 'node1', label: 'node1', type: 'graphin-circle'},
{id: 'node2', label: 'node2', type: 'graphin-circle'},
{id: 'node3', label: 'node3', type: 'graphin-circle'},
{id: 'node4', label: 'node4', type: 'graphin-circle'},
{id: 'node5', label: 'node5', type: 'graphin-circle'},
{id: 'node6', label: 'node6', type: 'graphin-circle'},
]
}
return (
<div>
<Graphin data={data} layout={layout}>
<DragNodeWithForce autoPin={autoPin} />
<Toolbar>
<Toolbar.Item>
被拖拽的节点,是否自动固定住
</Toolbar.Item>
<Toolbar.Item>
啊,这一集又没有一格是我呢
</Toolbar.Item>
</Toolbar>
<ClickBehavior/>
</Graphin>
</div>
);
};
export default Child
了解了基本的click事件其实已经可以解决80%的自定义交互的问题了,因为图交互这种事情基本都是很依赖鼠标点击边或者点的,把这一块做好后自定义事件会很容易,不比操作一个个实例差多少的!