245 lines
5.9 KiB
Vue
245 lines
5.9 KiB
Vue
<template>
|
|
<!-- 树形图谱 -->
|
|
<el-tabs v-model="activeName" @tab-click="handleTabClick">
|
|
<el-tab-pane label="树形图谱" name="first">
|
|
<div id="container"></div>
|
|
</el-tab-pane>
|
|
<el-tab-pane label="统计信息" name="second">
|
|
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
</template>
|
|
|
|
<script>
|
|
import G6 from '@antv/g6';
|
|
import request from "@/utils/request";
|
|
import {tripletToTree} from "@/utils/common";
|
|
|
|
let data;
|
|
var vm;
|
|
var graph;
|
|
export default {
|
|
data() {
|
|
return {
|
|
activeName: 'first'
|
|
}
|
|
},
|
|
created() {
|
|
vm = this;
|
|
},
|
|
mounted() {
|
|
|
|
},
|
|
methods: {
|
|
queryTreeData(ontologyId) {
|
|
if (graph) {
|
|
return;
|
|
}
|
|
request({
|
|
url: `/nebula_model/findtreebyontologyid/${ontologyId}`,
|
|
method: 'post',
|
|
data: {}
|
|
}).then(res => {
|
|
data = {
|
|
id: "root",
|
|
properties: {tagName: '根节点'},
|
|
children: tripletToTree({
|
|
nodes: res.data.nodes,
|
|
relations: res.data.relations,
|
|
idName: 'vid',
|
|
sourceName: 'srcId',
|
|
targetName: 'dstId'
|
|
})
|
|
};
|
|
vm.initTree();
|
|
});
|
|
|
|
},
|
|
destroyTree() {
|
|
if (graph) {
|
|
graph = null;
|
|
document.getElementById('container').innerHTML = "";
|
|
}
|
|
},
|
|
initTree() { // 初始化数据
|
|
const container = document.getElementById('container');
|
|
const width = container.scrollWidth;
|
|
const height = (container.scrollHeight || 800) - 20;
|
|
graph = new G6.TreeGraph({
|
|
container: 'container',
|
|
width,
|
|
height,
|
|
modes: {
|
|
default: [
|
|
'drag-canvas',
|
|
'zoom-canvas',
|
|
{
|
|
type: 'drag-node',
|
|
enableDelegate: true,
|
|
},
|
|
],
|
|
},
|
|
defaultNode: {
|
|
size: 25,
|
|
anchorPoints: [
|
|
[0, 0.5],
|
|
[1, 0.5],
|
|
],
|
|
style: {
|
|
|
|
fill: '#68BDF6',
|
|
stroke: '#4b4b4b',
|
|
},
|
|
},
|
|
defaultEdge: {
|
|
type: 'cubic-horizontal',
|
|
style: {
|
|
stroke: '#A3B1BF',
|
|
},
|
|
},
|
|
nodeStateStyles: {
|
|
closest: {
|
|
fill: '#004f80',
|
|
},
|
|
},
|
|
layout: {
|
|
type: 'compactBox',
|
|
direction: 'LR',
|
|
getId: function getId(d) {
|
|
return d.id;
|
|
},
|
|
getHeight: function getHeight() {
|
|
return 16;
|
|
},
|
|
getWidth: function getWidth() {
|
|
return 16;
|
|
},
|
|
getVGap: function getVGap() {
|
|
return 10;
|
|
},
|
|
getHGap: function getHGap() {
|
|
return 100;
|
|
},
|
|
},
|
|
});
|
|
|
|
graph.node(function (node) {
|
|
node.tagName = (node.properties && node.properties.tagName) ? node.properties.tagName : '未命名';
|
|
return {
|
|
label: node.tagName,
|
|
labelCfg: {
|
|
offset: 10,
|
|
position: node.children && node.children.length > 0 ? 'left' : 'right',
|
|
},
|
|
};
|
|
});
|
|
|
|
graph.data(data);
|
|
graph.render();
|
|
graph.fitView();
|
|
|
|
let minDisNode;
|
|
graph.on('node:dragstart', (e) => {
|
|
minDisNode = undefined;
|
|
});
|
|
graph.on('node:drag', (e) => {
|
|
minDisNode = undefined;
|
|
const item = e.item;
|
|
const model = item.getModel();
|
|
const nodes = graph.getNodes();
|
|
let minDis = Infinity;
|
|
nodes.forEach((inode) => {
|
|
graph.setItemState(inode, 'closest', false);
|
|
const node = inode.getModel();
|
|
if (node.id === model.id) return;
|
|
const dis = (node.x - e.x) * (node.x - e.x) + (node.y - e.y) * (node.y - e.y);
|
|
if (dis < minDis) {
|
|
minDis = dis;
|
|
minDisNode = inode;
|
|
}
|
|
});
|
|
// console.log('minDis', minDis, minDisNode);
|
|
if (minDis < 2000) graph.setItemState(minDisNode, 'closest', true);
|
|
else minDisNode = undefined;
|
|
});
|
|
|
|
graph.on('node:dragend', (e) => {
|
|
if (!minDisNode) {
|
|
// descriptionDiv.innerHTML = '失败,拖动的节点附近没有节点';
|
|
return;
|
|
}
|
|
const item = e.item;
|
|
const id = item.getID();
|
|
const data = graph.findDataById(id);
|
|
// if the minDisNode is a descent of the dragged node, return
|
|
let isDescent = false;
|
|
const minDisNodeId = minDisNode.getID();
|
|
console.log('dragend', minDisNodeId, isDescent, data, id);
|
|
|
|
G6.Util.traverseTree(data, (d) => {
|
|
if (d.id === minDisNodeId) isDescent = true;
|
|
});
|
|
if (isDescent) {
|
|
vm.$message.error("目标节点是被拖动节点的后代");
|
|
return;
|
|
}
|
|
graph.removeChild(id);
|
|
|
|
setTimeout(() => {
|
|
const newParentData = graph.findDataById(minDisNodeId);
|
|
let newChildren = newParentData.children;
|
|
if (newChildren) newChildren.push(data);
|
|
else newChildren = [data];
|
|
graph.updateChildren(newChildren, minDisNodeId);
|
|
vm.$message.success("操作成功");
|
|
}, 600);
|
|
});
|
|
|
|
if (typeof window !== 'undefined')
|
|
window.onresize = () => {
|
|
if (!graph || graph.get('destroyed')) return;
|
|
if (!container || !container.scrollWidth || !container.scrollHeight) return;
|
|
graph.changeSize(container.scrollWidth, container.scrollHeight - 20);
|
|
};
|
|
},
|
|
destroyTreeGraph() {
|
|
|
|
},
|
|
handleTabClick(tab, event) {
|
|
console.log(tab, event);
|
|
},
|
|
submitUpdate() { // 更新
|
|
vm.$parent.submitUpdateEdge(vm.modifyCmd);
|
|
},
|
|
}
|
|
}
|
|
|
|
</script>
|
|
|
|
<style>
|
|
|
|
.node-box {
|
|
overflow: hidden;
|
|
}
|
|
|
|
.form-title {
|
|
font-size: 16px;
|
|
margin: 15px 0;
|
|
|
|
}
|
|
|
|
.add-attribute-box {
|
|
margin-top: 10px;
|
|
color: #409EFF;
|
|
cursor: pointer;
|
|
text-align: right;
|
|
}
|
|
|
|
.info-content > div {
|
|
margin-bottom: 5px;
|
|
line-height: 20px;
|
|
}
|
|
|
|
|
|
</style>
|