应用场景
在做组织关系图时,经常会遇到关系图的实现要求,就是要将人与人或者组织与组织或者人与组织之间的关系进行一一展示。已知的就是节点和关系。
需求分析
最近在写后台管理系统时,遇到一个需求,就是要实现关系图:
如下图所示:
在前年写天眼查功能时,我也遇到过这种需求,不过当时不知道可以用插件来实现,因此功能并未完全开发:
代码实现
直接上代码:
1.安装
1.1 Npm 方式
npm i relation-graph
文章来源:https://www.toymoban.com/news/detail-515686.html
1.2 Yarn方式
yarn add relation-graph
文章来源地址https://www.toymoban.com/news/detail-515686.html
2.使用
2.1 html部分代码
<template>
<div>
<div style="height:calc(100vh - 50px);">
<RelationGraph ref="seeksRelationGraph" :options="graphOptions" :on-node-click="onNodeClick" :on-line-click="onLineClick" />
</div>
</div>
</template>
2.2 script部分代码
<script>
import RelationGraph from 'relation-graph';//引入插件
export default {
name: 'Demo',
components: { RelationGraph },//注册插件
data() {
return {
//设置插件的参数
graphOptions: {
allowSwitchLineShape: true,
allowSwitchJunctionPoint: true,
defaultJunctionPoint: 'border'
// 这里可以参考"Graph 图谱"中的参数进行设置:http://relation-graph.com/#/docs/graph
}
}
},
mounted() {
this.showSeeksGraph()
},
methods: {
showSeeksGraph() {
//需要指定 节点参数和连接线的参数
var __graph_json_data = {
rootId: 'a',
nodes: [
// node配置选项:http://relation-graph.com/#/docs/node
// node支持通过插槽slot完全自定义,示例:http://relation-graph.com/#/demo/adv-slot
{ id: 'a', text: 'A', borderColor: 'yellow' },
{ id: 'b', text: 'B', color: '#43a2f1', fontColor: 'yellow' },
{ id: 'c', text: 'C', nodeShape: 1, width: 80, height: 60 },
{ id: 'e', text: 'E', nodeShape: 0, width: 150, height: 150 }
],
lines: [
// link配置选项:http://relation-graph.com/#/docs/link
{ from: 'a', to: 'b', text: '关系1', color: '#43a2f1' },
{ from: 'a', to: 'c', text: '关系2' },
{ from: 'a', to: 'e', text: '关系3' },
{ from: 'b', to: 'e', color: '#67C23A' }
]
}
this.$refs.seeksRelationGraph.setJsonData(__graph_json_data, (seeksRGGraph) => {
// Called when the relation-graph is completed
})
},
onNodeClick(nodeObject, $event) {
console.log('onNodeClick:', nodeObject)
},
onLineClick(linkObject, $event) {
console.log('onLineClick:', linkObject)
}
}
}
</script>
3.如果要需要展示鼠标移入后展示节点细节,则可以用下面的方式
3.1 html部分代码
<template>
<a-spin :spinning="loading">
<div
style="height: calc(100vh - 130px); border: 1px solid #ebebeb"
ref="myPage"
>
<RelationGraph
ref="seeksRelationGraph"
:options="graphOptions"
:on-node-click="onNodeClick"
:on-line-click="onLineClick"
>
<div
slot="node"
slot-scope="{ node }"
style="height: 100%"
@mouseover="showNodeTips(node, $event)"
@mouseout="hideNodeTips(node, $event)"
>
<div
style="
border-radius: 50%;
cursor: pointer;
word-break: break-all;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
height: 100%;
font-size: 12px;
overflow: hidden;
"
>
{{
node.text &&
node.text
.replace('https://www.', '')
.replace('http://www.', '')
.replace('.com', '')
.replace('.html', '')
.split('/').length > 1
? node.text
.replace('https://www.', '')
.replace('http://www.', '')
.replace('.com', '')
.replace('.html', '')
.split('/')[
node.text
.replace('https://www.', '')
.replace('http://www.', '')
.replace('.com', '')
.replace('.html', '')
.split('/').length - 1
]||node.text
.replace('https://www.', '')
.replace('http://www.', '')
.replace('.com', '')
.replace('.html', '')
.split('/')[
node.text
.replace('https://www.', '')
.replace('http://www.', '')
.replace('.com', '')
.replace('.html', '')
.split('/').length - 2
]
: node.text
}}
</div>
</div>
<!-- <div
slot="bottomPanel"
style="
border-top: #efefef solid 1px;
height: 60px;
line-height: 60px;
text-align: center;
font-size: 18px;
background-color: #ffffff;
"
>
这里是底部插槽 slot="bottomPanel",可以自定义这里的内容
</div> -->
</RelationGraph>
</div>
<div
v-if="isShowNodeTipsPanel"
:style="{
left: nodeMenuPanelPosition.x + 'px',
top: nodeMenuPanelPosition.y + 'px',
}"
style="
z-index: 999;
padding: 10px;
background-color: #ffffff;
border: #eeeeee solid 1px;
box-shadow: 0px 0px 8px #cccccc;
position: absolute;
"
>
<div
style="
line-height: 25px;
padding-left: 10px;
color: #888888;
font-size: 12px;
"
>
节点名称:{{ currentNode.text }}
</div>
</div>
</a-spin>
</template>
3.2 js部分代码
<script>
import RelationGraph from 'relation-graph';
import { getRelationship } from '@/services/statistics';//我这边的接口地址,需要改成你自己的
export default {
components: { RelationGraph },
data() {
return {
loading: false,
data: [],
activeKey: '',
src: '',
isShowCodePanel: false,
isShowNodeTipsPanel: false,
nodeMenuPanelPosition: { x: 0, y: 0 },
currentNode: {},
graphOptions: {
allowSwitchLineShape: true,
allowSwitchJunctionPoint: true,
layouts: [
{
label: '中心',
layoutName: 'force', //布局方式(tree树状布局/center中心布局/force自动布局)
layoutClassName: 'seeks-layout-center', //当使用这个布局时,会将此样式添加到图谱上
defaultJunctionPoint: 'border', //默认的连线与节点接触的方式
defaultNodeShape: 0, //默认的节点形状,0:圆形;1:矩形
defaultLineShape: 1, //默认的线条样式(1:直线/2:样式2/3:样式3/4:折线/5:样式5/6:样式6)
centerOffset_y: 130, //根节点y坐标偏移量(针对项目配置单位为px)
min_per_width: 150, //节点距离限制:节点之间横向距离最小值
min_per_height: 180, //节点距离限制:节点之间纵向距离最小值
},
],
defaultNodeShape: 0, //默认的节点形状,0:圆形;1:矩形
defaultExpandHolderPosition: 'bottom', //节点展开关闭的按钮位置
defaultLineShape: 1, //默认的线条样式(1:直线/2:样式2/3:样式3/4:折线/5:样式5/6:样式6)
defaultJunctionPoint: 'tb', //默认的连线与节点接触的方式(border:边缘/ltrb:上下左右/tb:上下/lr:左右)当布局为树状布局时应使用tb或者lr,这样才会好看
defaultNodeBorderWidth: 0.2, //节点边框粗细
defaultcolor: 'rgba(0, 186, 189, 1)', //默认的线条颜色
defaultNodeColor: 'rgba(0, 206, 209, 1)', //默认的节点背景颜色
defaultNodeWidth: '80', //节点宽度
defaultNodeHeight: '80', //节点高度
defaultFocusRootNode: false, //默认为根节点添加一个被选中的样式
moveToCenterWhenResize: true, //当图谱的大小发生变化时,是否重新让图谱的内容看起来居中
// 这里可以参考"Graph 图谱"中的参数进行设置
},
};
},
activated() {
this.showSeeksGraph();
},
methods: {
showNodeTips(nodeObject, $event) {
this.currentNode = nodeObject;
const _base_position = this.$refs.myPage.getBoundingClientRect();
this.isShowNodeTipsPanel = true;
this.nodeMenuPanelPosition.x = $event.clientX - _base_position.x + 10;
this.nodeMenuPanelPosition.y = $event.clientY - _base_position.y + 10;
},
hideNodeTips(nodeObject, $event) {
this.isShowNodeTipsPanel = false;
},
callback(val) {
this.activeKey = val;
this.showSeeksGraph();
},
//渲染节点和连接线
showSeeksGraph() {
getRelationship().then((res) => {
let nodes = res.node_list || [];
let links = res.edge_list || [];
var __graph_json_data = {
rootId: '0',
nodes: nodes,
links: links,
};
// 以上数据中的node和link可以参考"Node节点"和"Link关系"中的参数进行配置
this.$refs.seeksRelationGraph.setJsonData(
__graph_json_data,
(graphInstance) => {
// Called when the relation-graph is completed
setTimeout(() => {
graphInstance.stopAutoLayout();
}, 1000);
}
);
});
},
//点击节点触发的函数
onNodeClick(nodeObject, $event) {
const allLinks = this.$refs.seeksRelationGraph.getLinks();
allLinks.forEach((link) => {
// 还原所有样式
link.relations.forEach((line) => {
if (line.data.orignColor) {
line.color = line.data.orignColor;
}
if (line.data.orignFontColor) {
line.fontColor = line.data.orignColor;
}
if (line.data.orignLineWidth) {
line.lineWidth = line.data.orignLineWidth;
}
});
});
// 让与{nodeObject}相关的所有连线高亮
allLinks
.filter(
(link) => link.fromNode === nodeObject || link.toNode === nodeObject
)
.forEach((link) => {
link.relations.forEach((line) => {
line.data.orignColor = line.color;
line.data.orignFontColor = line.fontColor || line.color;
line.data.orignLineWidth = line.lineWidth || 1;
line.color = '#ff0000';
line.fontColor = '#ff0000';
line.lineWidth = 3;
});
});
// 有时候更改一些属性后,并不能马上同步到视图,这需要以下方法让视图强制根据数据同步到最新
this.$refs.seeksRelationGraph.getInstance().dataUpdated();
},
//店家连接线触发的函数
onLineClick(lineObject, $event) {
console.log('onLineClick:', lineObject);
// this.$notify({
// title: '点击连线:',
// type: 'success',
// message: '点击了线:' + linkObject.fromNode.text + ' to ' + linkObject.toNode.text
// });
},
},
};
</script>
3.3 css部分代码
<style lang="less" scoped>
.c-my-node2 {
border: none;
background-position: center center;
background-size: 100%;
height: 74px;
width: 74px;
border-radius: 40px;
}
.c-node-name2 {
width: 160px;
margin-left: -40px;
text-align: center;
margin-top: 85px;
position: absolute;
}
.c-node-menu-item {
line-height: 30px;
padding-left: 10px;
cursor: pointer;
color: #444444;
font-size: 14px;
border-top: #efefef solid 1px;
}
.c-node-menu-item:hover {
background-color: rgba(66, 187, 66, 0.2);
}
</style>
到了这里,关于vue插件——relation-graph——实现关系图功能——技能提升的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!