diff --git a/src/store/groupEvolution/index.js b/src/store/groupEvolution/index.js index dab3254..c1a9cf9 100644 --- a/src/store/groupEvolution/index.js +++ b/src/store/groupEvolution/index.js @@ -12,7 +12,6 @@ import { getGroupEvolutionGroupScaleChart, getGroupEvolutionTimeLine, getPostByUtcTime, - getStructuralEvolutionChart, getStructuralEvolutionAnalysisChart, getStructuralEvolutionAnalysisTimeLine, @@ -245,8 +244,7 @@ export const useGroupDiscoveryStore = defineStore("groupDiscovery", { return { id: node.name, label: node.name, - color: setColor(node.groupId), - cluster: parseInt(node.groupId) + type: node.groupId } }) }, @@ -270,21 +268,21 @@ export const useGroupStructureStore = defineStore("groupStructure", { type: "群体一", focusedTopic: "#中国海警首次登检菲律宾运补船只", innerNum: 20, - outerNum: 100, + outerNum: 100 }, { id: 2, type: "群体二", focusedTopic: "#外交部回应中国海警缴获菲土乓枪支", innerNum: 20, - outerNum: 100, + outerNum: 100 }, { id: 3, type: "群体三", focusedTopic: "#社会群体对中国海警缴获菲土乓枪支", innerNum: 20, - outerNum: 100, + outerNum: 100 } ], graph: {}, @@ -297,7 +295,7 @@ export const useGroupStructureStore = defineStore("groupStructure", { data: [0.3055, 0.3939, 0.5813, 0.6094, 0.6289], name: "", themeColor: "#2AB8FD" - }, + } ] }, chartsData: { @@ -567,7 +565,7 @@ export const useGroupStructureStore = defineStore("groupStructure", { async initializeStructuralEvolutionChart() { const res = await getStructuralEvolutionChart() this.chartData = { - xAxisData: res.data.xaxisData.map(item => utcStringToHHMMSS(item)), + xAxisData: res.data.xaxisData.map((item) => utcStringToHHMMSS(item)), seriesList: [ { name: "", @@ -575,7 +573,7 @@ export const useGroupStructureStore = defineStore("groupStructure", { themeColor: "#2AB8FD" } ], - yAxisRange: {min: 0, max: 1, interval: 0.2}, + yAxisRange: { min: 0, max: 1, interval: 0.2 } } }, diff --git a/src/utils/customePaint.js b/src/utils/customePaint.js index ce7e39c..5687192 100644 --- a/src/utils/customePaint.js +++ b/src/utils/customePaint.js @@ -54,18 +54,18 @@ export const paintLineFunction = function (ctx, needHideText) { this.drawOriginalLine(ctx, needHideText) //内置默认的绘制方法 //指定路径,用于鼠标检测选中 - // this.path = [ - // { x: this.source.cx, y: this.source.cy }, - // { x: this.target.cx, y: this.target.cy } - // ]; + this.path = [ + { x: this.source.cx, y: this.source.cy }, + { x: this.target.cx, y: this.target.cy } + ] // //绘制路径 - // ctx.beginPath(); - // ctx.moveTo(this.source.cx,this.source.cy); - // ctx.lineTo(this.target.cx,this.target.cy); - // this.setLineStyle(ctx); - // ctx.stroke(); + ctx.beginPath() + ctx.moveTo(this.source.cx, this.source.cy) + ctx.lineTo(this.target.cx, this.target.cy) + this.setLineStyle(ctx) + ctx.stroke() // //绘制连线上文字(内部方法) - // this.paintTextOnLineWithAngle(ctx, this.source, this.target); + this.paintTextOnLineWithAngle(ctx, this.source, this.target) } diff --git a/src/views/GroupEvolution/component/groupGraph.vue b/src/views/GroupEvolution/component/groupGraph.vue index afe81cb..d4fe42e 100644 --- a/src/views/GroupEvolution/component/groupGraph.vue +++ b/src/views/GroupEvolution/component/groupGraph.vue @@ -6,7 +6,7 @@ colorMap[node.cluster], borderColor: "200,50,50", borderWidth: 0, selected: { @@ -131,73 +130,85 @@ const registEvents = () => { }) } const runForceLayout = () => { - let viewCenter = graphVis.getViewCenter() - let simulation = graphVis.getSimulationLayout() - let curForceSimulator = simulation.forceSimulation() - curForceSimulator - .nodes(graphVis.nodes) - .force("center", simulation.forceCenter(viewCenter.x, viewCenter.y)) - .force("charge", simulation.forceManyBody().strength(-550).theta(0.85)) // manyBodyReuse|forceManyBody .distanceMin(300).distanceMax(400).theta(0.9) - .force("link", simulation.forceLink(graphVis.links).distance(120).strength(0.35)) //.distance(120).strength(0.15) - .force( - "collide", - simulation.forceCollide().radius((d) => d.radius + 5) - ) //.iterations(5) - .force("x", simulation.forceX()) - .force("y", simulation.forceY()) - .alphaDecay(0.02) //设置 alpha 衰减率.迭代150,默认0.0228 - //.alphaMin(0.005) //须要在 [0, 1] 之间。若是没有指定 min 则返回当前的最小 alpha 值,默认为 0.001. 在仿真内部,会不断的减少 alpha 值直到 alpha 值小于 最小 alpha - .velocityDecay(0.15) //默认为 0.4,较低的衰减系数可使得迭代次数更多,其布局结果也会更理性,可是可能会引发数值不稳定从而致使震荡。 - - curForceSimulator.alpha(1).restart() - - curForceSimulator.on("tick", () => { - if (graphVis) { - graphVis.refreshView() // 刷新视图 + const layoutConfig = { strength: -500, ajustCluster: true } + //执行异步布局计算 + graphVis.excuteWorkerLayout( + graphVis.getGraphData(), + "simulation", + layoutConfig, + false, + function () { + graphVis.zoomFit() //布局结束缩放居中 } - }) - - curForceSimulator.on("end", () => { - curForceSimulator.alpha(0) - curForceSimulator.stop() - }) - forceSimulator = curForceSimulator + ) } +// 根据节点的cluster属性进行分组 +const clusterAnalyze = () => { + graphVis.removeAllGroup() // 清除原有分组 + // 创建cluster到nodes的映射 + const clusterNodesMap = new Map() + graphVis.nodes.forEach((node) => { + const cluster = parseInt(node.type) + if (!clusterNodesMap.has(cluster)) { + clusterNodesMap.set(cluster, []) + } + clusterNodesMap.get(cluster).push(node) + }) + const colorMap = { + 0: "50,141,120", // 绿色 + 1: "133,129,48", // 黄色 + 6: "12,112,144" // 蓝色 + } + clusterNodesMap.forEach((nodes, cluster) => { + const color = colorMap[cluster] + nodes.forEach((node) => { + node.fillColor = color + node.color = color + }) + let group = graphVis.addNodesInGroup(nodes, { + shape: "polygon", //circle|rect|polygon|bubbleset + color: color, + alpha: 0.3 + }) + group.smoothPath = false //拟合平滑曲线(耗性能) + }) + graphVis.autoGroupLayout(graphVis.nodes) +} + +const createGraph = () => { + if (!graphVis) { + graphVis = new GraphVis({ + container: document.getElementById("container"), + licenseKey: "hbsy", + config: defaultConfig + }) + } + graphVis.setDragHideLine(false) //拖拽时隐藏连线 + graphVis.setShowDetailScale(0.1) //展示细节的比例 + graphVis.setZoomRange(0.1, 5) //缩放区间 + registCustomePaintFunc() //注册自定义绘图方法 + registEvents() +} + +const initChart = () => { + createGraph() + graphVis.addGraph({ ...toRaw(graph.value) }) + runForceLayout() + clusterAnalyze() +} + // 添加更新图表的函数 const updateChart = (newGraphData) => { if (!graphVis) { initChart() return } - // 清除现有图表 graphVis.clearAll() - - // 添加新数据 graphVis.addGraph({ ...toRaw(newGraphData) }) - graphVis.autoGroupLayout(toRaw(newGraphData).nodes) - + graphVis.zoomFit() // 重新运行力导向布局 runForceLayout() -} -const initChart = () => { - const createGraph = () => { - if (!graphVis) { - graphVis = new GraphVis({ - container: document.getElementById("container"), - licenseKey: "hbsy", - config: defaultConfig - }) - } - graphVis.setDragHideLine(false) //拖拽时隐藏连线 - graphVis.setShowDetailScale(0.1) //展示细节的比例 - graphVis.setZoomRange(0.05, 5) //缩放区间 - registCustomePaintFunc() //注册自定义绘图方法 - registEvents() - } - - createGraph() - graphVis.addGraph({ ...toRaw(graph.value) }) - runForceLayout() + clusterAnalyze() } let lastLength = 0 //记录上一次的长度 diff --git a/src/views/GroupEvolution/groupStructure/index.vue b/src/views/GroupEvolution/groupStructure/index.vue index 99c5b0b..9cbf27c 100644 --- a/src/views/GroupEvolution/groupStructure/index.vue +++ b/src/views/GroupEvolution/groupStructure/index.vue @@ -74,25 +74,25 @@