<template>
|
<div class="atlasBox">
|
<div id="container" class="container" v-show="!showEcharts">
|
<svg class="keywords" @mousemove="listener($event)">
|
<a href="javascript:void(0)" v-for="(tag, index) in tags" :key="index"
|
@contextmenu="removeClick($event, tag)" @click="nodeClick(tag)">
|
<text class="text" :x="tag.x" :y="tag.y" :font-size="20 * (600 / (600 - tag.z))"
|
:fill-opacity="(400 + tag.z) / 600" :fill="tag.color">{{ tag.text }}</text>
|
</a>
|
</svg>
|
</div>
|
<div class="graphicBox" v-show="showEcharts">
|
<div class="konwReturn fl">
|
<el-link @click="showEcharts = false">
|
<i class="el-icon-d-arrow-left"></i>
|
</el-link>
|
当前领域:{{ targetName }}
|
</div>
|
<div id="graphicContent" v-loading="g_loading" class="graphicContent">
|
<RelationGraph ref="graphRef" :options="graphOptions" :on-node-expand="onNodeExpand"
|
:on-node-collapse="onNodeCollapse">
|
</RelationGraph>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import G6 from '@antv/g6';
|
import { kg_getGraph, kg_queryGraphResult } from '@/api/mapView/map.js';
|
import RelationGraph from 'relation-graph'
|
export default {
|
components: { RelationGraph },
|
data() {
|
return {
|
width: null,
|
height: null,
|
tags: [],
|
showEcharts: false,
|
speedX: Math.PI / 360,
|
speedY: Math.PI / 360,
|
CX: 600,
|
CY: 300,
|
RADIUS: 200,
|
ZRADIUS: 200,
|
targetName: null,
|
// 图谱
|
g_loading: true,
|
demoname: '---',
|
graphOptions: {
|
layout:
|
{
|
label: '中心',
|
layoutName: 'tree',
|
layoutClassName: 'seeks-layout-center',
|
defaultJunctionPoint: 'border',
|
defaultNodeShape: 0,
|
defaultLineShape: 1,
|
from: 'left',
|
max_per_width: 300,
|
min_per_height: 40
|
},
|
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)'
|
}
|
}
|
},
|
|
mounted() {
|
|
// ;
|
this.setResizeStart();
|
},
|
methods: {
|
nodeClick(tag) {
|
this.showEcharts = true;
|
this.targetName = tag.text
|
this.g_loading = true
|
this.getGraphData(tag.text)
|
|
},
|
|
getGraphData(name) {
|
|
|
|
this.graphOptions.layout.max_per_width = this.width
|
kg_queryGraphResult(
|
{ domain: name }
|
).then(response => {
|
if (response.data.code != 200) return
|
this.g_loading = false;
|
const data = response.data.data
|
if (!this.width) {
|
this.width = document.getElementById('container').innerWidth;
|
}
|
const obj = data.node.filter(item => {
|
if (item.name == name) {
|
return item
|
}
|
})
|
this.getGraphicNodes(data.node, data.relationship, obj)
|
})
|
},
|
onNodeCollapse(node, e) {
|
// const graphInstance = this.$refs.graphRef.getInstance();
|
// graphInstance.doLayout();
|
},
|
// 通过onNodeExpand事件监听节点的展开事件,在被展开的时候有选择的去从后台获取数据,如果已经从后台加载过数据,则让当前图谱根据当前的节点重新布局
|
onNodeExpand(node, e) {
|
const graphInstance = this.$refs.graphRef.getInstance();
|
// 根据具体的业务需要决定是否需要从后台加载数据
|
if (!node.data.isNeedLoadDataFromRemoteServer) {
|
console.log('这个节点的子节点已经加载过了');
|
graphInstance.doLayout();
|
return;
|
}
|
// 判断是否已经动态加载数据了
|
if (node.data.childrenLoaded) {
|
console.log('这个节点的子节点已经加载过了');
|
graphInstance.doLayout();
|
return;
|
}
|
// this.g_loading = true;
|
node.data.childrenLoaded = true;
|
this.loadChildNodesFromRemoteServer(node);
|
},
|
loadChildNodesFromRemoteServer(node) {
|
var graphInstance = this.$refs.graphRef.getInstance();
|
graphInstance.doLayout();
|
},
|
getGraphicNodes(res, lines, obj) {
|
const std = [];
|
const ids = [];
|
|
lines.filter(item => {
|
|
if (ids.indexOf(item.sourceId) < 0) {
|
ids.push(item.sourceId)
|
}
|
if (obj && obj.length > 0) {
|
if (item.targetId == obj[0].uuid) {
|
ids.push(item.targetId)
|
}
|
}
|
|
})
|
|
res.filter(item => {
|
var poi = false;
|
if (item.poi && item.poi == 1) {
|
poi = true;
|
}
|
|
const expand = ids.indexOf(item.uuid) > -1 ? false : true
|
if (!expand) {
|
|
std.push({
|
// 'uuid': item.id ? item.id : new Date().getTime(),
|
'id': item.uuid,
|
'text': item.name,
|
// expandHolderPosition: 'right',
|
// expanded: true,
|
// data: { isNeedLoadDataFromRemoteServer: true, childrenLoaded: false },
|
})
|
} else {
|
std.push({
|
// 'uuid': item.id ? item.id : new Date().getTime(),
|
'id': item.uuid,
|
'text': item.name,
|
// expandHolderPosition: 'right',
|
// expanded: false,
|
// data: { isNeedLoadDataFromRemoteServer: true, childrenLoaded: false },
|
})
|
}
|
|
})
|
this.getGraphicLines(std, lines)
|
},
|
getGraphicLines(nodes, res) {
|
const std = [];
|
res.filter(item => {
|
std.push({
|
"from": "" + item.sourceId + "",
|
"to": "" + item.targetId + "",
|
"text": "包含",
|
})
|
|
})
|
const json_data = {
|
'rootId': 'a',
|
'nodes': nodes,
|
'lines': std
|
};
|
this.setGraphic(json_data)
|
},
|
setGraphic(res) {
|
|
|
|
setTimeout(() => {
|
|
this.$refs.graphRef.setJsonData(res, (graphInstance) => {
|
// 这些写上当图谱初始化完成后需要执行的代码
|
graphInstance.doLayout();
|
});
|
|
}, 1000);
|
|
|
setTimeout(() => {
|
|
var graphInstance = this.$refs.graphRef.getInstance();
|
|
}, 2000);
|
},
|
removeClick() { },
|
rotateX(speedX) {
|
var cos = Math.cos(speedX);
|
var sin = Math.sin(speedX);
|
for (let tag of this.tags) {
|
var y1 = (tag.y - this.CY) * cos - tag.z * sin + this.CY;
|
var z1 = tag.z * cos + (tag.y - this.CY) * sin;
|
tag.y = y1;
|
tag.z = z1;
|
}
|
},
|
rotateY(speedY) {
|
var cos = Math.cos(speedY);
|
var sin = Math.sin(speedY);
|
for (let tag of this.tags) {
|
var x1 = (tag.x - this.CX) * cos - tag.z * sin + this.CX;
|
var z1 = tag.z * cos + (tag.x - this.CX) * sin;
|
tag.x = x1;
|
tag.z = z1;
|
}
|
},
|
resizeWindow() {
|
if (this.showEcharts) return;
|
let height = document.getElementById('container').clientHeight;
|
let width = document.getElementById('container').clientWidth;
|
width = width * 0.85;
|
if (width > 1200) {
|
this.CX = width / 2;
|
}
|
height = height - 150;
|
this.CY = height / 2;
|
let radius = Math.min(this.CY, this.CX) / 2;
|
if (radius > 200) {
|
this.RADIUS = radius;
|
}
|
this.setCreateGraph();
|
},
|
setResizeStart() {
|
this.resizeWindow();
|
window.addEventListener('resize', this.resizeWindow);
|
this.setCreateGraph();
|
//使球开始旋转
|
const interval = setInterval(() => {
|
this.rotateX(this.speedX);
|
this.rotateY(this.speedY);
|
}, 17);
|
this.$once('hook:beforedestroy', () => {
|
interval && clearInterval(interval);
|
window.removeEventListener('resize', this.resizeWindow);
|
});
|
},
|
//图谱初始化
|
setCreateGraph() {
|
kg_getGraph({
|
command: 0,
|
pageIndex: 1,
|
pageSize: 5000,
|
}).then((response) => {
|
if (response.data.code != 200) return;
|
|
this.setGraphStart(response.data.data.nodeList);
|
});
|
},
|
listener(event) {
|
var x = event.clientX - this.CX;
|
var y = event.clientY - this.CY;
|
if (event.target.tagName == 'text') {
|
this.speedX = 0;
|
this.speedY = 0;
|
} else {
|
this.speedX = x * 0.00001 > 0 ? Math.min(this.RADIUS * 0.00002, x * 0.0001) : Math.max(-this.RADIUS * 0.00002, x * 0.0001);
|
this.speedY = y * 0.00001 > 0 ? Math.min(this.RADIUS * 0.00002, y * 0.0001) : Math.max(-this.RADIUS * 0.00002, y * 0.0001);
|
}
|
|
// var val = document.getElementById("removeLabel").style.display;
|
// if (val == "none") {
|
// document.getElementById("removeLabel").style.top = event.clientY - 20 + 'px';
|
// document.getElementById("removeLabel").style.left = event.clientX + 10 + 'px';
|
// }
|
},
|
setGraphStart(arr) {
|
const field = 'label';
|
const obj = arr.filter((item, index) => {
|
return arr.findIndex((i) => i[field] === item[field]) === index;
|
});
|
let tags = [];
|
const length = obj.length;
|
for (let i = 0; i < length; i++) {
|
let tag = {};
|
let k = -1 + (2 * (i + 1) - 1) / length;
|
let a = Math.acos(k);
|
let b = a * Math.sqrt(length * Math.PI);
|
tag.text = obj[i].label;
|
(tag.id = obj[i].id), (tag.label = obj[i].label), (tag.x = this.CX + this.RADIUS * Math.sin(a) * Math.cos(b));
|
tag.y = this.CY + this.RADIUS * Math.sin(a) * Math.sin(b);
|
tag.z = this.ZRADIUS * Math.cos(a);
|
tag.color = 'rgb(' + parseInt(Math.random() * 255) + ',' + parseInt(Math.random() * 255) + ',' + parseInt(Math.random() * 255) + ')';
|
tags.push(tag);
|
}
|
this.tags = [].concat(tags);
|
},
|
},
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
.atlasBox {
|
width: calc(100% - 20px);
|
height: calc(100% - 20px);
|
position: absolute;
|
margin: 10px;
|
border-radius: 5px;
|
|
// background: skyblue;
|
.container {
|
width: 100%;
|
height: 100%;
|
}
|
|
.keywords {
|
width: 100%;
|
height: 100%;
|
}
|
|
.keywords .text:hover {
|
font-size: 200%;
|
}
|
|
.SVGBox {
|
width: 100%;
|
height: 100%;
|
}
|
|
.graphicBox {
|
width: 100%;
|
height: 100%;
|
display: flex;
|
flex-direction: column;
|
|
.graphicContent {
|
padding: 10px;
|
flex: 1;
|
|
}
|
}
|
}
|
</style>
|