|
|
|
@ -196,7 +196,7 @@ |
|
|
|
<!-- {{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"/> |
|
|
|
<RelationGraph ref="graphRef" :options="graphOptions" :on-node-click="onNodeClick" :on-line-click="onLineClick"/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
@ -229,7 +229,7 @@ |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import RelationGraph, { RGJsonData, RGOptions } from 'relation-graph-vue3'; |
|
|
|
import RelationGraph, { RGJsonData, RGOptions ,Layout} 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,7 +239,103 @@ 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, |
|
|
|
@ -249,24 +345,10 @@ export default { |
|
|
|
}, |
|
|
|
data() { |
|
|
|
return { |
|
|
|
resizeTimer: null, |
|
|
|
|
|
|
|
getpoinName :"模糊综合评价方法", |
|
|
|
testoptions: { |
|
|
|
layout: { |
|
|
|
layoutName: 'force', |
|
|
|
animate: false, // 必须关闭动画 |
|
|
|
maxIterations: 50, // 仍控制在合理范围 |
|
|
|
fit: true, |
|
|
|
padding: 80, // 增加画布边距,防止节点贴边 |
|
|
|
// --- 核心:放大两倍间距 --- |
|
|
|
idealEdgeLength: 200, // 🔥 从 100 → 200(直接翻倍) |
|
|
|
nodeRepulsion: 150000, // 🔥 大幅提升斥力,防止压缩 |
|
|
|
gravity: 0.05, // 🔽 极低引力,避免向中心聚集 |
|
|
|
stiffness: 200, // 保持边“硬”,防止拉伸变形 |
|
|
|
damping: 0.85, // 高阻尼抑制震荡 |
|
|
|
distanceMin: 30, |
|
|
|
distanceMax: 600 // 允许更大空间 |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
direction: "rtl", |
|
|
|
// visGraph实例对象 |
|
|
|
visGraph: null, |
|
|
|
@ -301,35 +383,7 @@ export default { |
|
|
|
header: '提示信息', // 提示表头 |
|
|
|
data: [] //提示内部的数据 |
|
|
|
}, |
|
|
|
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, |
|
|
|
}, |
|
|
|
graphOptions, |
|
|
|
currentNode: {}, // 选中的节点对象 |
|
|
|
attrbutes: [],//选中节点或连线的属性列表 |
|
|
|
currentLink: {},// 选中的连线对象 |
|
|
|
@ -401,25 +455,8 @@ 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) |
|
|
|
@ -626,6 +663,27 @@ 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; |
|
|
|
@ -672,6 +730,13 @@ export default { |
|
|
|
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, |
|
|
|
@ -695,36 +760,19 @@ export default { |
|
|
|
links:links |
|
|
|
} |
|
|
|
|
|
|
|
this.$refs.graphRef.setJsonData(data); |
|
|
|
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); |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
// 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); |
|
|
|
// }) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|