|
|
|
@ -193,10 +193,10 @@ |
|
|
|
<div :class="full ? 'full-screen' : 'show-box'"> |
|
|
|
<div style="width: 100%;height: 100%;"> |
|
|
|
<div class="gContainer"> |
|
|
|
<!-- {{graphData.nodes}}--> |
|
|
|
<!-- <RelationGraph ref="graphRef" :options="graphOptions" :nodes="graphData.nodes" :links="graphData.links"--> |
|
|
|
<!-- :on-node-click="onNodeClick" :on-line-click="onLineClick" />--> |
|
|
|
<RelationGraph ref="graphRef" :options="graphOptions" :on-node-click="onNodeClick" :on-line-click="onLineClick"/> |
|
|
|
<!-- {{graphData.nodes}}--> |
|
|
|
<!-- <RelationGraph ref="graphRef" :options="graphOptions" :nodes="graphData.nodes" :links="graphData.links"--> |
|
|
|
<!-- :on-node-click="onNodeClick" :on-line-click="onLineClick" />--> |
|
|
|
<RelationGraph ref="graphRef" :options="testoptions" :on-node-click="onNodeClick" :on-line-click="onLineClick"/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
@ -229,7 +229,7 @@ |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import RelationGraph, { RGJsonData, RGOptions ,Layout} from 'relation-graph-vue3'; |
|
|
|
import RelationGraph, { RGJsonData, RGOptions } from 'relation-graph-vue3'; |
|
|
|
import LayoutFactory from '@/assets/js/graphvis.layout.min.js' |
|
|
|
import { config } from '@/assets/defaultConfig.js' |
|
|
|
import { demoData } from '@/assets/demo2.js' |
|
|
|
@ -239,103 +239,7 @@ import { getAllTitle, getDocInfo } from "@/api/api/doc"; |
|
|
|
import {getDomainGraphTest, getpoinAll, getpoinByName} from "@/api/api/graph"; |
|
|
|
import { Picture } from "@element-plus/icons-vue"; |
|
|
|
import { selectAticleByRelation } from '@/api/api/article' |
|
|
|
class MyForceLayout extends Layout.ForceLayouter { |
|
|
|
constructor(arg1, arg2, arg3) { |
|
|
|
console.log('MyForceLayout..................'); |
|
|
|
super(arg1, arg2, arg3); |
|
|
|
} |
|
|
|
resetCalcNodes() { |
|
|
|
// 以下代码会在力学布局开始前重置forCalcNodes,forCalcNodes用于频繁的计算, |
|
|
|
// 而visibleNodes中的节点是响应式对象会导致性能低下,所以这里将visibleNodes转换为forCalcNodes用于力学布局迭代计算 |
|
|
|
this.forCalcNodes = []; |
|
|
|
this.calcNodeMap = new WeakMap(); |
|
|
|
this.visibleNodes.forEach(thisNode => { |
|
|
|
const calcNode = { |
|
|
|
rgNode: thisNode, |
|
|
|
Fx: 0, |
|
|
|
Fy: 0, |
|
|
|
x: thisNode.x, |
|
|
|
y: thisNode.y, |
|
|
|
ignoreForce: (thisNode.dragging || (this.justLayoutSingleNode && !thisNode.singleNode)), |
|
|
|
force_weight: thisNode.force_weight || 1, |
|
|
|
forceCenterOffset_X: (thisNode.width || thisNode.el.offsetWidth || 60) / 2, |
|
|
|
forceCenterOffset_Y: (thisNode.height || thisNode.el.offsetHeight || 60) / 2, |
|
|
|
fixed: thisNode.fixed || false, |
|
|
|
myColor: thisNode.color |
|
|
|
}; |
|
|
|
this.forCalcNodes.push(calcNode); |
|
|
|
this.calcNodeMap.set(thisNode, calcNode); |
|
|
|
}); |
|
|
|
} |
|
|
|
calcNodesPosition() { |
|
|
|
const nodes = this.forCalcNodes; |
|
|
|
for (let i=0;i<this.forCalcNodes.length;i++) { |
|
|
|
const __node1 = this.forCalcNodes[i]; |
|
|
|
if (__node1.ignoreForce) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (__node1.fixed) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
for (let j = 0; j < this.forCalcNodes.length;j++) { |
|
|
|
// 循环点,计算i点与j点点斥力及方向 |
|
|
|
if (i !== j) { |
|
|
|
const __node2 = this.forCalcNodes[j]; |
|
|
|
if (__node2.ignoreForce) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
/** |
|
|
|
* 任意两点之间都会在这里进行作用力分析 |
|
|
|
* 你可以在这里根据你自己的规则为他们施加作用力,施加作用力的方式有两种: |
|
|
|
* 斥力: this.addGravityByNode(__node1, __node2); |
|
|
|
* 牵引力: this.addElasticByLine(__node1, __node2, 0.5); |
|
|
|
*/ |
|
|
|
// 示例:两点之间不能靠的太近,所以要给节点间施加斥力 |
|
|
|
this.addGravityByNode(__node1, __node2); |
|
|
|
if (__node1.myColor === __node2.myColor) { |
|
|
|
// 示例:如果颜色相同,则他们不能离得太远,所以要施加牵引力 |
|
|
|
this.addElasticByLine( |
|
|
|
__node1, |
|
|
|
__node2, |
|
|
|
1 |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const graphOptions = { |
|
|
|
debug: true, |
|
|
|
backgrounImageNoRepeat: true, |
|
|
|
moveToCenterWhenRefresh: true, |
|
|
|
zoomToFitWhenRefresh: true, |
|
|
|
useAnimationWhenRefresh: false, |
|
|
|
defaultLineColor: 'rgba(255, 255, 255, 0.6)', |
|
|
|
defaultNodeColor: 'rgba(255, 255, 255, 0.6)', |
|
|
|
defaultNodeBorderWidth: 1, |
|
|
|
defaultNodeBorderColor: 'rgba(255, 255, 255, 0.3)', |
|
|
|
defaultNodeFontColor: '#1b7702', |
|
|
|
defaultNodeShape: 0, |
|
|
|
defaultNodeWidth: 60, |
|
|
|
defaultNodeHeight: 60, |
|
|
|
toolBarDirection: 'h', |
|
|
|
toolBarPositionH: 'right', |
|
|
|
toolBarPositionV: 'bottom', |
|
|
|
defaultPloyLineRadius: 10, |
|
|
|
defaultLineShape: 1, |
|
|
|
layout: { |
|
|
|
layoutName: 'force', |
|
|
|
from: 'center', |
|
|
|
maxLayoutTimes: 100, |
|
|
|
// disableLiveChanges: true, |
|
|
|
force_node_repulsion: 2.26, // 全局设置,节点之间的斥力系数,默认为1,建议合理的取值范围:0.1 -- 10 |
|
|
|
force_line_elastic: 0.01 |
|
|
|
|
|
|
|
// 全局设置,线条的牵引系数,默认为1, 建议合理的取值范围:0.1 -- 10 |
|
|
|
} |
|
|
|
}; |
|
|
|
export default { |
|
|
|
components: { |
|
|
|
leftInfo, |
|
|
|
@ -345,10 +249,40 @@ export default { |
|
|
|
}, |
|
|
|
data() { |
|
|
|
return { |
|
|
|
resizeTimer: null, |
|
|
|
|
|
|
|
getpoinName :"模糊综合评价方法", |
|
|
|
|
|
|
|
testoptions: { |
|
|
|
debug: true, |
|
|
|
backgrounImageNoRepeat: true, |
|
|
|
moveToCenterWhenRefresh: true, |
|
|
|
zoomToFitWhenRefresh: true, |
|
|
|
useAnimationWhenRefresh: false, |
|
|
|
defaultLineColor: 'rgba(255, 255, 255, 0.6)', |
|
|
|
defaultNodeColor: 'rgba(255, 255, 255, 0.6)', |
|
|
|
defaultNodeBorderWidth: 1, |
|
|
|
defaultNodeBorderColor: 'rgba(255, 255, 255, 0.3)', |
|
|
|
defaultNodeFontColor: '#1b7702', |
|
|
|
defaultNodeShape: 0, |
|
|
|
defaultNodeWidth: 100, |
|
|
|
defaultNodeHeight: 100, |
|
|
|
toolBarDirection: 'h', |
|
|
|
toolBarPositionH: 'right', |
|
|
|
toolBarPositionV: 'bottom', |
|
|
|
defaultPloyLineRadius: 300, |
|
|
|
defaultLineShape: 1, |
|
|
|
layout: { |
|
|
|
layoutName: 'force', |
|
|
|
from: 'center', |
|
|
|
maxLayoutTimes: 100, // 设置为0表示不自动布局 |
|
|
|
// 或者调整力导向布局参数使其更稳定 |
|
|
|
force_node_repulsion: 7000, // 增加节点斥力 |
|
|
|
force_line_elastic: 0.01, // 减小线条弹性 |
|
|
|
force_gravity_center: 0.01, // 减小重力中心 |
|
|
|
force_no_overlap: 0.5, // 防止重叠 |
|
|
|
force_is_3d: false, |
|
|
|
force_center: [0, 0], |
|
|
|
force_auto_restart: false // 禁止自动重新启动布局 |
|
|
|
} |
|
|
|
}, |
|
|
|
direction: "rtl", |
|
|
|
// visGraph实例对象 |
|
|
|
visGraph: null, |
|
|
|
@ -383,7 +317,35 @@ export default { |
|
|
|
header: '提示信息', // 提示表头 |
|
|
|
data: [] //提示内部的数据 |
|
|
|
}, |
|
|
|
graphOptions, |
|
|
|
graphOptions: { |
|
|
|
debug: false, |
|
|
|
lineUseTextPath: true, |
|
|
|
layout: { |
|
|
|
layoutName: 'tree', |
|
|
|
from: 'top', |
|
|
|
levelDistance: 200, // 层与层之间的垂直间距 |
|
|
|
nodeDistance: 150, // 同一层级的水平间距 |
|
|
|
min_per_width: 120, // 最小水平间距(固定值) |
|
|
|
max_per_width: 120, // 最大水平间距(固定值,强制均匀分布) |
|
|
|
min_per_height: 300, // 最小垂直间距(固定值) |
|
|
|
max_per_height: 300, // 最大垂直间距(固定值,强制对齐) |
|
|
|
disableDrag: true, // 禁止拖动节点(可选) |
|
|
|
align: 'center', // 居中排列 |
|
|
|
fixed: false, // 允许自动布局调整 |
|
|
|
}, |
|
|
|
defaultlineWidth: 2, |
|
|
|
defaultLineShape: 1, |
|
|
|
defaultNodeShape: 0, |
|
|
|
defaultLineFontSize: 80, |
|
|
|
defaultNodeBorderWidth: 0, |
|
|
|
defaultLineColor: 'rgb(255,255,255)', |
|
|
|
defaultNodeColor: 'rgba(0, 206, 209, 1)', |
|
|
|
lineLengths: 100, |
|
|
|
defaultNodeFontSize: '20px', // 全局默认字体大小 |
|
|
|
toolBarPositionH: 'right', |
|
|
|
toolBarPositionV: 'top', |
|
|
|
disableNodeClickEffect: true, |
|
|
|
}, |
|
|
|
currentNode: {}, // 选中的节点对象 |
|
|
|
attrbutes: [],//选中节点或连线的属性列表 |
|
|
|
currentLink: {},// 选中的连线对象 |
|
|
|
@ -455,8 +417,25 @@ export default { |
|
|
|
handleNodeClick(node) { |
|
|
|
console.log(node); |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
loadPng() { |
|
|
|
this.visGraph.saveImage(); |
|
|
|
}, |
|
|
|
// 获取所有的知识节点信息 |
|
|
|
async drawGraphData() { |
|
|
|
this.graphData = this.demoData; |
|
|
|
if (this.visGraph === null) { |
|
|
|
this.createGraph(); |
|
|
|
this.visGraph.drawData(this.graphData); |
|
|
|
this.visGraph.incremaNodesCodinate(this.graphData.nodes); |
|
|
|
this.reLayout(); |
|
|
|
} else { |
|
|
|
this.createGraph(); |
|
|
|
this.visGraph.drawData(this.graphData); |
|
|
|
this.visGraph.incremaNodesCodinate(this.graphData.nodes); |
|
|
|
this.reLayout(); |
|
|
|
} |
|
|
|
this.loading = false; |
|
|
|
}, |
|
|
|
// 创建全局绘图客户端对象 |
|
|
|
createGraph() { |
|
|
|
this.visGraph = new VisGraph(document.getElementById('graph-panel'), this.config) |
|
|
|
@ -663,27 +642,6 @@ export default { |
|
|
|
} |
|
|
|
return res |
|
|
|
}, |
|
|
|
async stopForceIfNeed() { |
|
|
|
const graphInstance = this.$refs.graphRef.getInstance(); |
|
|
|
await graphInstance.stopAutoLayout(); |
|
|
|
}, |
|
|
|
async updateLayouterOptions() { |
|
|
|
await this.stopForceIfNeed(); |
|
|
|
const graphInstance = this.$refs.graphRef.getInstance(); |
|
|
|
graphInstance.layouter.maxLayoutTimes = this.graphOptions.layout.maxLayoutTimes; |
|
|
|
graphInstance.layouter.force_node_repulsion = this.graphOptions.layout.force_node_repulsion; |
|
|
|
graphInstance.layouter.force_line_elastic = this.graphOptions.layout.force_line_elastic; |
|
|
|
setTimeout(async() => { |
|
|
|
await graphInstance.startAutoLayout(); |
|
|
|
}, 500); |
|
|
|
}, |
|
|
|
async resetNodeColor() { |
|
|
|
const graphInstance = this.$refs.graphRef.getInstance(); |
|
|
|
for (const node of graphInstance.getNodes()) { |
|
|
|
node.color = ['red', 'yellow', 'blue'][Math.floor(Math.random() * 3)]; |
|
|
|
} |
|
|
|
await this.updateLayouterOptions(); |
|
|
|
} |
|
|
|
}, |
|
|
|
created() { |
|
|
|
var that = this; |
|
|
|
@ -726,54 +684,62 @@ export default { |
|
|
|
getpoinByName(this.getpoinName).then((res) => { |
|
|
|
let nodes = [] |
|
|
|
let links = [] |
|
|
|
for (let i = 0;i<res.nodes.length;i++){ |
|
|
|
if (res.nodes[i].type=="keyword" && res.nodes[i].text!=this.getpoinName){ |
|
|
|
for (let i = 0; i < res.nodes.length; i++) { |
|
|
|
if (res.nodes[i].type == "keyword" && res.nodes[i].text != this.getpoinName) { |
|
|
|
continue |
|
|
|
} |
|
|
|
var level = 0; |
|
|
|
if(res.nodes[i].type=="agency"){ |
|
|
|
level = 2 |
|
|
|
} |
|
|
|
if(res.nodes[i].type=="author"){ |
|
|
|
level = 2 |
|
|
|
} |
|
|
|
let t_data = { |
|
|
|
id:res.nodes[i].id, |
|
|
|
text:res.nodes[i].text, |
|
|
|
color:this.getColor(res.nodes[i].type), |
|
|
|
id: res.nodes[i].id, |
|
|
|
text: res.nodes[i].text, |
|
|
|
color: this.getColor(res.nodes[i].type), |
|
|
|
} |
|
|
|
nodes.push(t_data) |
|
|
|
} |
|
|
|
for (let i = 0;i<res.links.length;i++){ |
|
|
|
for (let i = 0; i < res.links.length; i++) { |
|
|
|
let t_data = { |
|
|
|
from:res.links[i].from, |
|
|
|
to:res.links[i].to, |
|
|
|
text:res.links[i].text, |
|
|
|
from: res.links[i].from, |
|
|
|
to: res.links[i].to, |
|
|
|
text: res.links[i].text, |
|
|
|
} |
|
|
|
links.push(t_data) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var data = { |
|
|
|
nodes:nodes, |
|
|
|
links:links |
|
|
|
var data = { |
|
|
|
nodes: nodes, |
|
|
|
links: links |
|
|
|
} |
|
|
|
|
|
|
|
const graphInstance = this.$refs.graphRef.getInstance(); |
|
|
|
// 使用你的自定义力学布局 |
|
|
|
graphInstance.setLayouter(new MyForceLayout(graphInstance.layouter.layoutOptions, graphInstance.options, graphInstance)) |
|
|
|
this.stopForceIfNeed(); |
|
|
|
graphInstance.setJsonData(data); |
|
|
|
if (this.useBigData) { |
|
|
|
graphInstance.setZoom(30); |
|
|
|
} else { |
|
|
|
graphInstance.setZoom(80); |
|
|
|
} |
|
|
|
this.$refs.graphRef.setJsonData(data); |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// getpoinAll().then((res) => { |
|
|
|
// for (let i = 0;i<res.nodes.length;i++){ |
|
|
|
// let t_data = { |
|
|
|
// id:res.nodes[i].id, |
|
|
|
// text:res.nodes[i].text, |
|
|
|
// color:this.getColor(res.nodes[i].type), |
|
|
|
// } |
|
|
|
// res.nodes[i] = t_data |
|
|
|
// } |
|
|
|
// for (let i = 0;i<res.links.length;i++){ |
|
|
|
// let t_data = { |
|
|
|
// from:res.links[i].from, |
|
|
|
// to:res.links[i].to, |
|
|
|
// text:res.links[i].text, |
|
|
|
// } |
|
|
|
// res.links[i] = t_data |
|
|
|
// } |
|
|
|
// |
|
|
|
// |
|
|
|
// |
|
|
|
// var data = { |
|
|
|
// nodes:res.nodes, |
|
|
|
// links:res.links |
|
|
|
// } |
|
|
|
// |
|
|
|
// this.$refs.graphRef.setJsonData(data); |
|
|
|
// }) |
|
|
|
|
|
|
|
|
|
|
|
}, |
|
|
|
@ -828,13 +794,13 @@ export default { |
|
|
|
bottom: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.legend-wrap>.legend-item { |
|
|
|
.legend-wrap > .legend-item { |
|
|
|
height: 24px; |
|
|
|
line-height: 24px; |
|
|
|
font-size: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.legend-item>.item-dot { |
|
|
|
.legend-item > .item-dot { |
|
|
|
float: left; |
|
|
|
display: inline-block; |
|
|
|
height: 20px; |
|
|
|
@ -844,7 +810,7 @@ export default { |
|
|
|
cursor: pointer; |
|
|
|
} |
|
|
|
|
|
|
|
.legend-item>.item-label { |
|
|
|
.legend-item > .item-label { |
|
|
|
display: inline-block; |
|
|
|
float: left; |
|
|
|
margin-left: 5px; |
|
|
|
@ -862,14 +828,14 @@ export default { |
|
|
|
font-size: 14px; |
|
|
|
} |
|
|
|
|
|
|
|
.tip-wrap>.tip-header { |
|
|
|
.tip-wrap > .tip-header { |
|
|
|
height: 30px; |
|
|
|
line-height: 30px; |
|
|
|
padding: 5px 10px; |
|
|
|
border-bottom: 1px solid #ddd; |
|
|
|
} |
|
|
|
|
|
|
|
.tip-wrap>.tip-body { |
|
|
|
.tip-wrap > .tip-body { |
|
|
|
padding: 0 10px 10px; |
|
|
|
} |
|
|
|
|
|
|
|
@ -898,7 +864,7 @@ export default { |
|
|
|
cursor: pointer; |
|
|
|
} |
|
|
|
|
|
|
|
.right-menu-layer button>i { |
|
|
|
.right-menu-layer button > i { |
|
|
|
margin-right: 5px; |
|
|
|
} |
|
|
|
|
|
|
|
@ -1109,8 +1075,7 @@ select { |
|
|
|
} |
|
|
|
|
|
|
|
.icon1 { |
|
|
|
margin-left: 45%; |
|
|
|
; |
|
|
|
margin-left: 45%;; |
|
|
|
cursor: pointer; |
|
|
|
color: #ffffff; |
|
|
|
width: 2vw; |
|
|
|
@ -1209,7 +1174,6 @@ loadPng:hover { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.label { |
|
|
|
font-size: 1vw; |
|
|
|
text-overflow: ellipsis; |
|
|
|
@ -1240,7 +1204,7 @@ input::-webkit-input-placeholder { |
|
|
|
} |
|
|
|
|
|
|
|
.el-tree--highlight-current { |
|
|
|
.el-tree-node.is-current>.el-tree-node__content { |
|
|
|
.el-tree-node.is-current > .el-tree-node__content { |
|
|
|
background-color: rgba(255, 255, 255, 0.21); |
|
|
|
color: #fff; |
|
|
|
|
|
|
|
@ -1337,13 +1301,14 @@ input::-webkit-input-placeholder { |
|
|
|
width: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
td{ |
|
|
|
td { |
|
|
|
border: 1px solid #000; |
|
|
|
} |
|
|
|
|
|
|
|
tr { |
|
|
|
margin-bottom: 2vh; |
|
|
|
} |
|
|
|
|
|
|
|
.el-tree--highlight-current { |
|
|
|
background: no-repeat; |
|
|
|
} |
|
|
|
|