Merge branch 'master' of http://172.16.20.1:3000/duanhao/SocialNetworks_duan
This commit is contained in:
commit
f24cce9202
116
src/assets/package/layoutParamsDict.js
Normal file
116
src/assets/package/layoutParamsDict.js
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
//布局算法的参数定义
|
||||
export const layoutParamsDict ={
|
||||
'hierarchical':[ //层级布局
|
||||
{'name':'layerSpace','value': 150,'type':'number','label':'层间距'},
|
||||
{'name':'nodeSpace','value': 80,'type':'number','label':'点间距'},
|
||||
{'name':'sortType','value': 'selected','type':'array','label':'排序类型',
|
||||
'types':[
|
||||
{'label':'指定点','value':'selected'},
|
||||
{'label':'度大小','value':'hubsize'},
|
||||
{'label':'连线方向','value':'directed'}
|
||||
]
|
||||
},
|
||||
{'name':'direction','value': 'UD','type':'array','label':'方向',
|
||||
'types':[
|
||||
{'label':'上下','value':'UD'},
|
||||
{'label':'下上','value':'DU'},
|
||||
{'label':'左右','value':'LR'},
|
||||
{'label':'右左','value':'RL'}
|
||||
]
|
||||
}
|
||||
],
|
||||
'grid':[ //网格布局
|
||||
{'name':'layerSpace','value': 120,'type':'number','label':'层间距'},
|
||||
{'name':'nodeSpace','value': 140,'type':'number','label':'点间距'}
|
||||
],
|
||||
'concentric':[ //同心圆布局
|
||||
{'name':'maxNodeSize','value': 70,'type':'number','label':'节点大小'}
|
||||
],
|
||||
'fastForce':[ //网络布局
|
||||
{'name':'linkDistance','value': 150,'type':'number','label':'连线长度'},
|
||||
{'name':'charge','value': -450,'type':'number','label':'吸引力'},
|
||||
{'name':'friction','value': 0.85,'type':'decimal','label':'排斥力'},
|
||||
{'name':'linkStrength','value': 0.1,'type':'decimal','label':'连线强度'},
|
||||
{'name':'gravity','value': 0.05,'type':'decimal','label':'中心引力'}
|
||||
],
|
||||
'simulation':[ //力导向布局
|
||||
{'name':'strength','value': -800,'type':'number','label':'吸引力'},
|
||||
{'name':'linkDistance','value': 150,'type':'number','label':'连线长度'},
|
||||
{'name':'ajustCluster','value': false,'type':'array','label':'类型分组',
|
||||
'types':[
|
||||
{'label':'是','value':true},
|
||||
{'label':'否','value':false}
|
||||
]
|
||||
}
|
||||
],
|
||||
'kawakai':[ //最优路径布局
|
||||
{'name':'sizeScale','value': 1.5,'type':'number','label':'缩放比例'}
|
||||
],
|
||||
'circle':[ //环形布局
|
||||
{'name':'scale','value': 1.2,'type':'number','label':'缩放比例'},
|
||||
{'name':'ordering','value': 'degree','type':'array','label':'排序方式',
|
||||
'types':[
|
||||
{'label':'度大小排序','value':'degree'},
|
||||
{'label':'拓扑排序','value':'topology'}
|
||||
]
|
||||
}
|
||||
],
|
||||
'arf':[
|
||||
{'name':'neighberForce','value': 5.0,'type':'number','label':'邻边引力'},
|
||||
{'name':'attraction','value': 0.05,'type':'number','label':'向心力'},
|
||||
{'name':'forceScale','value': 5.0,'type':'number','label':'缩放比例'}
|
||||
],
|
||||
'tree':[ //树形布局
|
||||
{'name':'layerSpace','value': 150,'type':'number','label':'层间距'},
|
||||
{'name':'nodeSpace','value': 80,'type':'number','label':'点间距'},
|
||||
{'name':'direction','value': 'UD','type':'array','label':'方向',
|
||||
'types':[
|
||||
{'label':'上下','value':'UD'},
|
||||
{'label':'下上','value':'DU'},
|
||||
{'label':'左右','value':'LR'},
|
||||
{'label':'右左','value':'RL'}
|
||||
]
|
||||
}
|
||||
],
|
||||
'avoidlap':[ //避免重叠
|
||||
{'name':'maxPadding','value': 5,'type':'number','label':'节点间距'}
|
||||
],
|
||||
'dagre':[ //流程图布局
|
||||
{'name':'nodesep','value': 10,'type':'number','label':'点间距'},
|
||||
{'name':'ranksep','value': 100,'type':'number','label':'层间距'},
|
||||
{'name':'nodeSize','value': 50,'type':'number','label':'节点大小'},
|
||||
{'name':'rankdir','value': 'TB','type':'array','label':'排列方向',
|
||||
'types':[
|
||||
{'label':'上下','value':'TB'},
|
||||
{'label':'下上','value':'BT'},
|
||||
{'label':'左右','value':'LR'},
|
||||
{'label':'右左','value':'RL'}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
//获取默认的布局参数
|
||||
export const getLayoutDefaultConfig = function(layoutType){
|
||||
let layoutConfig = {};
|
||||
layoutParamsDict[layoutType].forEach(param=>{
|
||||
layoutConfig[param.name] = param.value;
|
||||
});
|
||||
return layoutConfig;
|
||||
};
|
||||
|
||||
//获取布局参数列表
|
||||
export const getLayoutParams = function(layoutType){
|
||||
return layoutParamsDict[layoutType];
|
||||
};
|
||||
|
||||
//布局算法列表
|
||||
export const layoutTypeList = [
|
||||
{label:'快速弹性布局',value:'fastForce',icon:'el-icon-orange'},
|
||||
{label:'力导向布局',value:'simulation',icon:'el-icon-orange'},
|
||||
{label:'最优路径布局',value:'kawakai',icon:'el-icon-cpu'},
|
||||
//{label:'球面引力布局',value:'arf',icon:'el-icon-orange'},
|
||||
{label:'层级布局',value:'hierarchical',icon:'el-icon-share'},
|
||||
{label:'中心圆布局',value:'concentric',icon:'el-icon-bangzhu'},
|
||||
{label:'去除重叠',value:'avoidlap',icon:'el-icon-copy-document'}
|
||||
];
|
||||
|
|
@ -211,7 +211,6 @@ export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
|
|||
this.timeList = res.data
|
||||
},
|
||||
|
||||
//根据时间参数获取节点数据
|
||||
async initialGraphByUtcTime(utcTime = "") {
|
||||
const setColor = (groupId) => {
|
||||
const colorMap = {
|
||||
|
|
@ -237,16 +236,23 @@ export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
|
|||
}
|
||||
return false
|
||||
})
|
||||
.map((node) => ({
|
||||
.map((node) => {
|
||||
return {
|
||||
id: node.name,
|
||||
label: node.name,
|
||||
color: setColor(node.groupId)
|
||||
}))
|
||||
color: setColor(node.groupId),
|
||||
cluster: parseInt(node.groupId)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 通过时间来获取帖文列表
|
||||
//根据时间参数获取贴文数据
|
||||
async initialPostByUtcTime(utcTime) {}
|
||||
async initialPostByUtcTime(utcTime) {
|
||||
const res = await getPostByUtcTime(utcTime)
|
||||
if (res.code != 200) return
|
||||
this.posts = res.data
|
||||
}
|
||||
},
|
||||
persist: true // 开启持久化
|
||||
})
|
||||
|
|
|
|||
|
|
@ -17,36 +17,23 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
defineProps,
|
||||
defineEmits,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
nextTick,
|
||||
ref,
|
||||
toRaw,
|
||||
watchEffect,
|
||||
watch
|
||||
} from "vue"
|
||||
import { defineProps, defineEmits, onUnmounted, ref, toRaw, watch } from "vue"
|
||||
import { storeToRefs } from "pinia"
|
||||
import { convertToUtcIsoString } from "@/utils/transform"
|
||||
import { paintNodeFunction, paintLineFunction } from "@/utils/customePaint"
|
||||
import { demoData } from "@/assets/customeGraph/data"
|
||||
import TimeAxis from "@/components/timeAxis.vue"
|
||||
import GraphVis from "@/assets/package/graphvis.esm.min.js"
|
||||
|
||||
const props = defineProps({
|
||||
store: {
|
||||
required: true
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(["click:pointerDownAndSlide"])
|
||||
// 解构 store 中的 state
|
||||
const { timeList, graph } = storeToRefs(props.store)
|
||||
let graphVis = null
|
||||
let forceSimulator = null
|
||||
let currentSelectNode = ref(null)
|
||||
let isGraphVisReady = false // 添加一个标志位
|
||||
const defaultConfig = {
|
||||
node: {
|
||||
label: {
|
||||
|
|
@ -65,7 +52,7 @@ const defaultConfig = {
|
|||
borderWidth: 2,
|
||||
borderColor: "100,250,100",
|
||||
showShadow: true, // 是否展示阴影
|
||||
shadowBlur: 30, //阴影范围大小
|
||||
shadowBlur: 10, //阴影范围大小
|
||||
shadowColor: "50,250,30" // 选中是的阴影颜色
|
||||
}
|
||||
},
|
||||
|
|
@ -77,7 +64,7 @@ const defaultConfig = {
|
|||
font: "normal 11px KaiTi", // 字体大小及类型
|
||||
background: "255,255,255" //文字背景色(设置后文字居中,一般与画布背景色一致)
|
||||
},
|
||||
lineType: "curver", //straight
|
||||
lineType: "straight", // curver
|
||||
showArrow: false,
|
||||
lineWidth: 2,
|
||||
colorType: "both",
|
||||
|
|
@ -177,46 +164,20 @@ const runForceLayout = () => {
|
|||
// 添加更新图表的函数
|
||||
const updateChart = (newGraphData) => {
|
||||
if (!graphVis) {
|
||||
initChart();
|
||||
return;
|
||||
initChart()
|
||||
return
|
||||
}
|
||||
// 清除现有图表
|
||||
graphVis.clearAll();
|
||||
graphVis.clearAll()
|
||||
|
||||
// 添加新数据
|
||||
graphVis.addGraph({ ...toRaw(newGraphData) });
|
||||
graphVis.addGraph({ ...toRaw(newGraphData) })
|
||||
graphVis.autoGroupLayout(toRaw(newGraphData).nodes)
|
||||
|
||||
// 重新运行力导向布局
|
||||
runForceLayout();
|
||||
runForceLayout()
|
||||
}
|
||||
const initChart = () => {
|
||||
const getGroupCenters = (groupCount, width, height, radius = 200) => {
|
||||
// 三组分布在三角形顶点
|
||||
const angleStep = (2 * Math.PI) / groupCount
|
||||
const centerX = width / 2
|
||||
const centerY = height / 2
|
||||
return Array.from({ length: groupCount }).map((_, i) => ({
|
||||
x: centerX + Math.cos(i * angleStep) * radius,
|
||||
y: centerY + Math.sin(i * angleStep) * radius
|
||||
}))
|
||||
}
|
||||
const assignNodePositions = (nodes, groupCenters) => {
|
||||
const groupMap = {}
|
||||
nodes.forEach((node) => {
|
||||
const groupIdx = node.groupId || 0
|
||||
if (!groupMap[groupIdx]) groupMap[groupIdx] = []
|
||||
groupMap[groupIdx].push(node)
|
||||
})
|
||||
Object.entries(groupMap).forEach(([groupIdx, groupNodes]) => {
|
||||
const center = groupCenters[groupIdx]
|
||||
groupNodes.forEach((node, i) => {
|
||||
// 每组节点在各自中心附近随机分布
|
||||
node.x = center.x + Math.random() * 80 - 40
|
||||
node.y = center.y + Math.random() * 80 - 40
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const createGraph = () => {
|
||||
if (!graphVis) {
|
||||
graphVis = new GraphVis({
|
||||
|
|
@ -227,31 +188,27 @@ const initChart = () => {
|
|||
}
|
||||
graphVis.setDragHideLine(false) //拖拽时隐藏连线
|
||||
graphVis.setShowDetailScale(0.1) //展示细节的比例
|
||||
graphVis.setZoomRange(0.1, 5) //缩放区间
|
||||
graphVis.setZoomRange(0.05, 5) //缩放区间
|
||||
registCustomePaintFunc() //注册自定义绘图方法
|
||||
registEvents()
|
||||
}
|
||||
|
||||
// const groupCount = 3 // 分组数量
|
||||
// const width = 900,
|
||||
// height = 500 // 画布大小
|
||||
// const groupCenters = getGroupCenters(groupCount, width, height)
|
||||
// assignNodePositions(graph.value.nodes, groupCenters)
|
||||
createGraph()
|
||||
console.log(graph.value)
|
||||
|
||||
graphVis.addGraph({ ...toRaw(graph.value) })
|
||||
runForceLayout()
|
||||
}
|
||||
|
||||
let lastLength = 0 //记录上一次的长度
|
||||
watch(
|
||||
graph,
|
||||
(newValue) => {
|
||||
if (newValue && Object.keys(newValue).length > 0) {
|
||||
updateChart(newValue);
|
||||
if (newValue && newValue.nodes.length > lastLength) {
|
||||
updateChart(newValue)
|
||||
}
|
||||
lastLength = newValue.nodes.length
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
onUnmounted(() => {
|
||||
if (graphVis) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user