github.com/seeksdream/… github地址
relation-graph.com/#/docs/star… 文档地址
使用Vue + Relation Graph 基于这个组件库实现了一个类似于企查查的人物关系图谱
组件效果
Vue 代码
<template>
<div>
<div style="height:calc(100vh - 50px);">
<SeeksRelationGraph
ref="seeksRelationGraph"
:options="graphOptions"
:on-node-click="onNodeClick"
:on-line-click="onLineClick"
>
<div @mouseleave="onNodeMouseLeave(node,$event)" @mouseenter="onNodeMouseenter(node,$event)" class="slot_node" slot="node" slot-scope="{node}">
<div class="node_content">
{{ node.data.name }}
</div>
</div>
</SeeksRelationGraph>
</div>
</div>
</template>
<script>
import SeeksRelationGraph from 'relation-graph'
import tree from "@/utils/tree.js";
export default {
name: 'erdas',
components: {SeeksRelationGraph},
data() {
return {
isShowCodePanel: false,
graphOptions: {
defaultFocusRootNode: true,//默认选中根节点
defaultNodeWidth: 120,//默认节点宽度
defaultNodeHeight: 120,//默认节点高度
defaultNodeBorderWidth: 0,
defaultNodeColor: '#3ebde2',//默认圆背景色
allowSwitchLineShape: true,
allowSwitchJunctionPoint: true,
defaultLineShape: 1,
defaultLineWidth: 1, //默认线条粗细
'layouts': [
{
'label': '中心',
'layoutName': 'center',
'layoutClassName': 'seeks-layout-center'
}
],
defaultJunctionPoint: 'border'
// 这里可以参考"Graph 图谱"中的参数进行设置
},
processed_object: {
nodes: [], //节点数据
rootId: '',//rootId
links: [],//线条数据
},
}
},
mounted() {
this.showSeeksGraph()
},
methods: {
getDictLabel(dict, value) {
return tree.getDictLabel(dict, value)
},
onNodeMouseLeave(nodeObject, $event) {
//遍历节点 恢复样式
let id = nodeObject.id;
nodeObject.width = this.graphOptions.defaultNodeWidth;
nodeObject.height = this.graphOptions.defaultNodeHeight;
let line_s = this.$refs.seeksRelationGraph.getLines();
line_s.map(v => {
if (v.fromNode.id === id || v.toNode.id === id) {
v.relations.forEach(x => {
x.lineWidth = this.graphOptions.defaultLineWidth
x.styleClass = '';
})
}
})
},
onNodeMouseenter(nodeObject, $event) {
//遍历节点 找到归属的线条 加粗线条 放大节点
let id = nodeObject.id;
nodeObject.width = this.graphOptions.defaultNodeWidth + 30;
nodeObject.height = this.graphOptions.defaultNodeHeight + 30;
let line_s = this.$refs.seeksRelationGraph.getLines();
line_s.map(v => {
if (v.fromNode.id === id || v.toNode.id === id) {
v.relations.forEach(x => {
x.lineWidth = 3
x.styleClass = 'cg_line_fake';
})
}
})
},
getLineColor(dict, value) {
return tree.find((dict || []), value, 'dictValue')?.dictColor || value
},
showSeeksGraph(query) {
//关系类型(00表示参股,01表示法人,02表示经理,03表示执行董事,04表示监事,99表示其他) 字典模拟
let dict_list = [
{
dictCode: '0',
dictValue: '00',
dictLabel: '参股',
dictColor: '#f47349',
},
{
dictCode: '01',
dictValue: '01',
dictLabel: '法人',
dictColor: '#d0e3a0',
},
{
dictCode: '02',
dictValue: '02',
dictLabel: '经理',
},
{
dictCode: '03',
dictValue: '03',
dictLabel: '执行董事',
dictColor: ' #99cee0',
},
{
dictCode: '04',
dictValue: '04',
dictLabel: '监事',
},
{
dictCode: '05',
dictValue: '99',
dictLabel: '其他',
},
]
//模拟 后台请求的数据 根据类型处理颜色
let colors_bg = {
'0': '#0183fe',//nodeType为企业时的背景颜色
'1': '#f25a29',//nodeType为个人时节点的背景颜色
}
//mock数据 根据 Yapi文档格式的原数据
let __mock_json_data = {
rootId: '2', //根节点
nodes: [
{
nodeCode: '1', nodeType: '1', nodeName: '章泽天', relations: [
{begin: '1', end: '2', relationType: '01'},
{begin: '1', end: '2', relationType: '00'},
{begin: '1', end: '8', relationType: '00'},
{begin: '1', end: '4', relationType: '00'},
{begin: '1', end: '3', relationType: '00'},
]
},
{nodeCode: '2', nodeName: '北京天强坤泰投资管理有限公司', nodeType: '0'},
{nodeCode: '3', nodeName: '海南三亚天博产业私募基金管理有限公司', nodeType: '0'},
{nodeCode: '4', nodeName: '三亚天强企业管理合伙企业(有限合伙)', nodeType: '0'},
{nodeCode: '6', nodeName: '上海京东才奥电子商务有限公司', nodeType: '0'},
{
nodeCode: '7', nodeName: '刘强东',nodeType:1, relations: [
{begin: '7', end: '8', relationType: '00'},
{begin: '7', end: '6', relationType: '00'},
{begin: '7', end: '4', relationType: '00'},
{begin: '7', end: '4', relationType: '01'},
{begin: '7', end: '3', relationType: '00'},
{begin: '7', end: '2', relationType: '00'},
{begin: '7', end: '2', relationType: '01'},
{begin: '7', end: '2', relationType: '03'},
]
},
{nodeCode: '8', nodeName: '宿迁天强股权投资合伙企业(有限合伙)', nodeType: '0'},
],
}
//links数组临时存储
let links_temp = [];
//rooId存储
this.processed_object.rootId = __mock_json_data.rootId;
//将上面的数据处理成组件需要的数据格式
this.processed_object.nodes = __mock_json_data.nodes.map(x => {
x.id = x.nodeCode;
x.name = x.nodeName;
x.color = colors_bg[x.nodeType]; //背景色处理
//根节点处理 宽度放大
// if (x.nodeCode === __mock_json_data.rootId) {
// x.width = 150;
// x.height = 150;
// }
//将有节点映射关系的节点进行聚集处理成links
if (x.relations && x.relations.length) {
x.relations.map(v => {
v.from = x.nodeCode;
v.to = v.end;
v.lineWidth = 1;
v.text = this.getDictLabel(dict_list, v.relationType)//线条标签名处理
v.color = this.getLineColor(dict_list, v.relationType) //线条颜色处理
links_temp.push(v);//插入数据
});
}
x.data = JSON.parse(JSON.stringify(x)); //自定义节点需要
return x;
})
//赋值
this.processed_object.links = links_temp;
//不可以直接传入this.processed_object
let JSON_FORMAT = JSON.parse(JSON.stringify(this.processed_object))
this.$refs.seeksRelationGraph.setJsonData(JSON_FORMAT, (seeksRGGraph) => {
// 这些写上当图谱初始化完成后需要执行的代码
})
},
onNodeClick(nodeObject, $event) {
//重置options
// this.$refs.seeksRelationGraph.setJsonData(data)
},
onLineClick(lineObject, $event) {
// console.log('onLineClick:', lineObject)
}
}
}
</script>
<style lang="scss">
</style>
<style lang="scss" scoped>
::v-deep {
//线条上的文字大小
.c-rg-link-text {
font-size: 18px;
}
//线条默认改为虚线
.c-rg-line{
stroke-dasharray:5;
}
.cg_line_fake{
stroke-dasharray:none ;
}
//整体
.slot_node {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
//内容
.node_content{
}
}
</style>
组件效果