| | |
| | | <template> |
| | | <div class="atlasBox"></div> |
| | | <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 style="color: #409EFF;" 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(); |
| | | }); |
| | | |
| | | }, 200); |
| | | |
| | | |
| | | 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> |
| | | |
| | |
| | | position: absolute; |
| | | margin: 10px; |
| | | border-radius: 5px; |
| | | background: skyblue; |
| | | |
| | | // 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%; |
| | | position: relative; |
| | | display: flex; |
| | | flex-direction: column; |
| | | color: #409EFF; |
| | | |
| | | .graphicContent { |
| | | padding: 10px; |
| | | flex: 1; |
| | | |
| | | |
| | | } |
| | | } |
| | | } |
| | | </style> |