概述
最近项目里面有用到血缘图、企业图谱、关系图相关的业务开发,综合考虑最终采用开源库relation-graph,内置vue组件和react组件,使用起来很方便,由于部分示例代码在官网需要开会员才能看到,所以,想要实现对应的复杂功能,需要自己去看源码,要不就自己掏钱去购买会员,综合考虑,本着能白嫖绝不花钱的原则,还是看源码,这里主要总结常用的几个功能点。
最终效果
工具栏的相关的功能官网需要会员才能看到,我这直接把源码里面的对应功能找出来,这里做一期小总结,其他更加详细的配置项可以自行查看官网。
实现代码
js
<template>
<div>
<el-button type="primary" @click="handleClickFullScreen">全屏</el-button>
<el-button type="primary" @click="handleClickZoomAdd">+</el-button>
<el-button type="primary">{{ zoomNumber }}</el-button>
<el-button type="primary" @click="handleClickZoomDecrease">-</el-button>
<el-button type="primary" @click="handleClickRefresh">刷新</el-button>
<el-button type="primary" @click="handleClickDownLoad">下载</el-button>
<div
v-loading="g_loading"
style="
margin-top: 50px;
width: calc(100% - 10px);
height: calc(100vh - 140px);
"
>
<RelationGraph
ref="graphRef"
:options="graphOptions"
:on-node-expand="onNodeExpand"
:on-node-collapse="onNodeCollapse"
>
</RelationGraph>
</div>
</div>
</template>
<script>
export default {
name: "RelationGraphDemo",
components: {},
data() {
return {
g_loading: true,
zoomNumber: 100,
demoname: "---",
graphOptions: {
layout: {
label: "中心",
layoutName: "tree",
layoutClassName: "seeks-layout-center",
defaultJunctionPoint: "border",
defaultNodeShape: 0,
defaultLineShape: 1,
from: "left",
max_per_width: 400,
min_per_height: 10,
},
defaultLineMarker: {
markerWidth: 12,
markerHeight: 12,
refX: 6,
refY: 6,
data: "M2,2 L10,6 L2,10 L6,6 L2,2",
},
moveToCenterWhenRefresh: false,
defaultExpandHolderPosition: "right",
defaultNodeShape: 1,
defaultNodeWidth: 100,
defaultLineShape: 4,
defaultJunctionPoint: "lr",
defaultNodeBorderWidth: 0,
defaultLineColor: "rgba(0, 186, 189, 1)",
defaultNodeColor: "rgba(0, 206, 209, 1)",
},
};
},
created() {},
mounted() {
this.demoname = this.$route.params.demoname;
this.setGraphData();
},
methods: {
setGraphData() {
// 使用要点:通过节点属性expandHolderPosition: 'right' 和 expanded: false 可以让节点在没有子节点的情况下展示一个"展开"按钮
// 通过onNodeExpand事件监听节点,在被展开的时候有选择的去从后台获取数据,如果已经从后台加载过数据,则让当前图谱根据当前的节点重新布局
const __graph_json_data = {
rootId: "a",
nodes: [
{ id: "a", text: "a" },
{ id: "b", text: "b-固定数据展开/关闭" },
{ id: "b1", text: "b1" },
{ id: "b1-1", text: "b1-1" },
{ id: "b1-2", text: "b1-2" },
{ id: "b1-3", text: "b1-3" },
{ id: "b1-4", text: "b1-4" },
{ id: "b1-5", text: "b1-5" },
{ id: "b1-6", text: "b1-6" },
{ id: "b2", text: "b2" },
{ id: "b2-1", text: "b2-1" },
{ id: "b2-2", text: "b2-2" },
{ id: "c", text: "c-动态数据展开/关闭" },
{
id: "c1",
text: "c1-动态获取子节点",
expandHolderPosition: "right",
expanded: false,
data: {
isNeedLoadDataFromRemoteServer: true,
childrenLoaded: false,
},
},
{
id: "c2",
text: "c2-动态获取子节点",
expandHolderPosition: "right",
expanded: false,
data: {
isNeedLoadDataFromRemoteServer: true,
childrenLoaded: false,
},
},
{
id: "c3",
text: "c3-动态获取子节点",
expandHolderPosition: "right",
expanded: false,
data: {
isNeedLoadDataFromRemoteServer: true,
childrenLoaded: false,
},
},
],
lines: [
{ from: "a", to: "b" },
{ from: "b", to: "b1" },
{ from: "b1", to: "b1-1" },
{ from: "b1", to: "b1-2" },
{ from: "b1", to: "b1-3" },
{ from: "b1", to: "b1-4" },
{ from: "b1", to: "b1-5" },
{ from: "b1", to: "b1-6" },
{ from: "b", to: "b2" },
{ from: "b2", to: "b2-1" },
{ from: "b2", to: "b2-2" },
{ from: "a", to: "c" },
{ from: "c", to: "c1" },
{ from: "c", to: "c2" },
{ from: "c", to: "c3" },
],
};
console.log(JSON.stringify(__graph_json_data));
setTimeout(() => {
this.g_loading = false;
this.$refs.graphRef.setJsonData(__graph_json_data, (graphInstance) => {
// 这些写上当图谱初始化完成后需要执行的代码
});
}, 1000);
},
onNodeCollapse(node, e) {
this.$refs.graphRef.refresh();
},
// 通过onNodeExpand事件监听节点的展开事件,在被展开的时候有选择的去从后台获取数据,如果已经从后台加载过数据,则让当前图谱根据当前的节点重新布局
onNodeExpand(node, e) {
console.log("onNodeExpand:", node);
// 根据具体的业务需要决定是否需要从后台加载数据
if (!node.data.isNeedLoadDataFromRemoteServer) {
console.log("这个节点的子节点已经加载过了");
this.$refs.graphRef.refresh();
return;
}
// 判断是否已经动态加载数据了
if (node.data.childrenLoaded) {
console.log("这个节点的子节点已经加载过了");
this.$refs.graphRef.refresh();
return;
}
this.g_loading = true;
node.data.childrenLoaded = true;
this.loadChildNodesFromRemoteServer(node, (new_data) => {
this.g_loading = false;
this.$refs.graphRef
.getInstance()
.appendJsonData(new_data, (graphInstance) => {
// 这些写上当图谱初始化完成后需要执行的代码
});
});
},
loadChildNodesFromRemoteServer(node, callback) {
setTimeout(function () {
const _new_json_data = {
nodes: [
{
id: node.id + "-child-1",
text: node.id + "-的动态子节点1",
width: 150,
expanded: false,
expandHolderPosition: "right",
data: {
isNeedLoadDataFromRemoteServer: true,
childrenLoaded: false,
},
},
{
id: node.id + "-child-2",
text: node.id + "-的动态子节点2",
width: 150,
expandHolderPosition: "right",
expanded: false,
data: {
isNeedLoadDataFromRemoteServer: true,
childrenLoaded: false,
},
},
{
id: node.id + "-child-3",
text: node.id + "-的动态子节点3",
width: 150,
isNeedLoadDataFromRemoteServer: true,
expanded: false,//是否已经展开(用于懒加载子节点数据)
data: {
isNeedLoadDataFromRemoteServer: true,//是否需要远程接口获取数据
childrenLoaded: false,//节点是否已经加载过
},
},
],
lines: [
{
from: node.id,
to: node.id + "-child-1",
text: "动态子节点",
useTextPath: true,
styleClass: "self-line",
},
{
from: node.id,
to: node.id + "-child-2",
text: "动态子节点",
useTextPath: true,//最好加上,避免展开节点样式不对称
styleClass: "self-line",//展开折叠节点的样式名
lineWidth: 3,
},
{
from: node.id,
to: node.id + "-child-3",
text: "动态子节点",
useTextPath: true,
styleClass: "self-line",
lineWidth: 3,
},
],
};
callback(_new_json_data);
}, 300);
},
handleClickFullScreen() {
this.$refs.graphRef.getInstance().fullscreen();
},
handleClickZoomAdd() {
this.$refs.graphRef.getInstance().zoom(10);
this.zoomNumber = this.$refs.graphRef.getInstance().options.canvasZoom;
},
handleClickZoomDecrease() {
this.$refs.graphRef.getInstance().zoom(-10);
this.zoomNumber = this.$refs.graphRef.getInstance().options.canvasZoom;
},
handleClickRefresh() {
this.$refs.graphRef.getInstance().refresh();
this.zoomNumber = this.$refs.graphRef.getInstance().options.canvasZoom;
},
handleClickDownLoad() {
this.$refs.graphRef.getInstance().downloadAsImage("png");
},
},
};
</script>