需求:需要显示企业的关系图谱。(由于项目使用的Vue,所以感觉这个作者写的还不错)
1、安装relation-graph(http://relation-graph.com/):
npm install --save relation-graph
2、引入relation-graph:
import RelationGraph from 'relation-graph';
3、创建dom:
<template>
<div>
<div class="graph" ref="graph" style="height:calc(100vh - 50px);" @click="canvasClick">
<RelationGraph ref="seeksRelationGraph" :options="graphOptions" :on-node-click="onNodeClick" :on-line-click="onLineClick">
<div slot="node" class="node" slot-scope="{ node }" @mouseover="showNodeTips(node, $event)" @mouseout="hideNodeTips(node, $event)">
<div v-if="node.data.labels.includes('Company')" class="company-node">
{{ node.text }}
</div>
<div v-else class="human-node">{{ node.text }}</div>
</div>
</RelationGraph>
</div>
<div v-if="isShowNodeTipsPanel" :style="{ left: nodeMenuPanelPosition.x + 'px', top: nodeMenuPanelPosition.y + 'px' }" class="node-dialog">
<div>{{ currentNode.text }}</div>
</div>
</div>
</template>
4、js配置(数据来源于企查查的小米关系图谱数据):
<script>
import RelationGraph from 'relation-graph';
import { xiaomi } from './xiaomi';
export default {
name: 'RelationGraphIndex',
components: { RelationGraph },
data() {
return {
// 图谱配置
graphOptions: {
backgrounImage: require('@/assets/images/bg.webp'), // 水印
backgrounImageNoRepeat: true, // 只在右下角显示水印,不重复显示水印
allowShowMiniToolBar: true, // 是否显示工具栏
allowShowMiniView: true, // 是否显示缩略图
allowShowMiniNameFilter: false, // 是否显示搜索框
allowSwitchLineShape: true, // 是否在工具栏中显示切换线条形状的按钮
allowSwitchJunctionPoint: true, // 是否在工具栏中显示切换连接点位置的按钮
disableZoom: false, // 是否禁用图谱的缩放功能,这里特指通过鼠标滚轮进行缩放的功能,禁用后你依然可以通过图谱工具栏按钮进行缩放
disableDragNode: false, // 是否禁用图谱中节点的拖动
moveToCenterWhenResize: true, // 当图谱的大小发生变化时,是否重新让图谱的内容看起来居中
// defaultFocusRootNode: '', // 默认为根节点添加一个被选中的样式
allowShowZoomMenu: true, // 是否在右侧菜单栏显示放大缩小的按钮
isMoveByParentNode: true, // 是否在拖动节点后让子节点跟随
hideNodeContentByZoom: true, // 是否根据缩放比例隐藏节点内容
defaultNodeShape: 0, // 默认的节点形状,0:圆形;1:矩形
// defaultNodeColor: '', // 默认的节点背景颜色
// defaultNodeFontColor: '', // 默认的节点文字颜色
// defaultNodeBorderWidth: '2px', // 默认的节点边框粗细(像素)
// defaultNodeWidth: '40px', // 默认的节点宽度
// defaultNodeHeight: '40px', // 默认的节点高度
defaultJunctionPoint: 'border', // 默认的连线与节点接触的方式(border:边缘 / ltrb:上下左右 / tb:上下 / lr:左右)
// defaultExpandHolderPosition: 'right', // 默认的节点展开/关闭按钮位置(left/top/right/bottom)
// defaultLineColor: '', // 默认的线条颜色
// defaultLineWidth: '', // 默认线条粗细(px)
// defaultLineShape: '', // 默认的线条样式(1:直线/2:样式2/3:样式3/4:折线/5:样式5/6:样式6)
// defaultLineMarker: '', // 默认的线条箭头样式
// defaultShowLineLabel: '', // 默认是否显示连线文字
// 布局方式
layouts: [
{
layoutLabel: '自动布局', // 布局描述
layoutName: 'force', // 布局方式(tree树状布局/center中心布局/force自动布局)
layoutClassName: 'seeks-layout-force' // 当使用这个布局时,会将此样式添加到图谱上
}
]
},
// 选中点
currentNode: {},
// 显示提示弹框
isShowNodeTipsPanel: false,
// 节点位置
nodeMenuPanelPosition: { x: 0, y: 0 }
};
},
mounted() {
this.showSeeksGraph();
},
methods: {
/**
* 加载图谱
* @date 2022-10-21
* @returns {any}
*/
showSeeksGraph() {
let { nodes, relationships } = xiaomi;
nodes = nodes.map((item) => {
item.text = item.properties.name;
item.data = { ...item };
if (item.labels.includes('Company')) (item.borderColor = '#4ea2f0'), (item.color = '#4ea2f0'), (item.styleClass = 'company-node');
if (item.labels.includes('Human')) (item.borderColor = '#ff6060'), (item.color = '#ff6060'), (item.width = 75), (item.height = 75);
if (item.text === '小米科技有限责任公司') (item.borderColor = '#ffce7f'), (item.color = '#ff9e00');
return item;
});
relationships = relationships.map((item) => {
item.from = item.startNode;
item.to = item.endNode;
item.text = item.properties.role;
return item;
});
let centerIds = nodes.find((item) => item.text === '小米科技有限责任公司');
const obj = {
rootId: centerIds.id,
nodes,
links: relationships
};
// 以上数据中的node和link可以参考"Node节点"和"Link关系"中的参数进行配置
this.$refs.seeksRelationGraph.setJsonData(obj, (seeksRGGraph) => {
// console.log(seeksRGGraph);
});
},
/**
* 节点点击
* @date 2022-10-21
* @param {any} nodeObject
* @param {any} $event
* @returns {any}
*/
onNodeClick(nodeObject, $event) {
console.log('节点数据:', nodeObject);
const _all_nodes = this.$refs['seeksRelationGraph'].getNodes(),
_all_lines = this.$refs['seeksRelationGraph'].getLines();
const { lot } = nodeObject;
// 子集高亮
if (lot.childs && lot.childs.length) {
_all_nodes.forEach((thisNode) => {
let _isHideThisNode = false;
lot.childs.forEach((childNode) => {
if (thisNode.id === childNode.id || thisNode.id === nodeObject.id) {
_isHideThisNode = true;
}
if (lot.parent && thisNode.id === lot.parent.id) {
_isHideThisNode = true;
}
});
thisNode.opacity = _isHideThisNode ? 1 : 0.1;
});
} else {
// 父级及本身高亮
_all_nodes.forEach((thisNode) => {
let _isHideThisNode = false;
if (thisNode.id === nodeObject.id) {
_isHideThisNode = true;
}
if (lot.parent && thisNode.id === lot.parent.id) {
_isHideThisNode = true;
}
thisNode.opacity = _isHideThisNode ? 1 : 0.1;
});
}
},
/**
* 线条点击
* @date 2022-10-21
* @param {any} lineObject
* @param {any} $event
* @returns {any}
*/
onLineClick(lineObject, $event) {
console.log('线条数据:', lineObject);
},
/**
* 鼠标移入显示提示
* @date 2022-10-21
* @param {any} nodeObject
* @param {any} $event
* @returns {any}
*/
showNodeTips(nodeObject, $event) {
this.currentNode = nodeObject;
const _base_position = this.$refs.graph.getBoundingClientRect();
this.isShowNodeTipsPanel = true;
this.nodeMenuPanelPosition.x = $event.clientX - _base_position.x + 90;
this.nodeMenuPanelPosition.y = $event.clientY - _base_position.y - 20;
},
/**
* 鼠标移出隐藏提示
* @date 2022-10-21
* @param {any} nodeObject
* @param {any} $event
* @returns {any}
*/
hideNodeTips(nodeObject, $event) {
this.isShowNodeTipsPanel = false;
},
/**
* 点击图谱
* @date 2022-10-21
* @returns {any}
*/
canvasClick() {
const _all_nodes = this.$refs['seeksRelationGraph'].getNodes();
_all_nodes.forEach((thisNode) => {
let _isHideThisNode = true;
thisNode.opacity = _isHideThisNode ? 1 : 0.1;
});
}
}
};
</script>
5、scss样式:
<style lang="scss" scoped>
.graph {
position: relative;
}
.node {
height: 100%;
}
.company-node {
width: 100%;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
line-height: 17px;
cursor: pointer;
}
.human-node {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.node-dialog {
z-index: 9999;
padding: 10px;
background-color: #ffffff;
border: #eeeeee solid 1px;
box-shadow: 0px 0px 8px #cccccc;
position: absolute;
}
</style>
6、最终效果:
希望大佬看到有不对的地方,提出博主予以改正!