群体演化分析关系图组件封装完毕
This commit is contained in:
		
							parent
							
								
									f24cce9202
								
							
						
					
					
						commit
						3c6a07f45c
					
				| 
						 | 
				
			
			@ -12,10 +12,7 @@ import {
 | 
			
		|||
  getGroupEvolutionGroupScaleChart,
 | 
			
		||||
  getGroupEvolutionTimeLine,
 | 
			
		||||
  getPostByUtcTime,
 | 
			
		||||
 | 
			
		||||
  getStructuralEvolutionChart,
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  getGroupMemberInfoList,
 | 
			
		||||
  getGroupMemberTimeLine,
 | 
			
		||||
  getGroupMemberChart,
 | 
			
		||||
| 
						 | 
				
			
			@ -240,8 +237,7 @@ export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
 | 
			
		|||
          return {
 | 
			
		||||
            id: node.name,
 | 
			
		||||
            label: node.name,
 | 
			
		||||
            color: setColor(node.groupId),
 | 
			
		||||
            cluster: parseInt(node.groupId)
 | 
			
		||||
            type: node.groupId
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -265,21 +261,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
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    chartData: {
 | 
			
		||||
| 
						 | 
				
			
			@ -290,7 +286,7 @@ export const useGroupStructureStore = defineStore("groupStructure", {
 | 
			
		|||
          data: [0.3055, 0.3939, 0.5813, 0.6094, 0.6289],
 | 
			
		||||
          name: "",
 | 
			
		||||
          themeColor: "#2AB8FD"
 | 
			
		||||
        },
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    chartsData: {
 | 
			
		||||
| 
						 | 
				
			
			@ -541,7 +537,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: "",
 | 
			
		||||
| 
						 | 
				
			
			@ -549,7 +545,7 @@ export const useGroupStructureStore = defineStore("groupStructure", {
 | 
			
		|||
            themeColor: "#2AB8FD"
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        yAxisRange: {min: 0, max: 1, interval: 0.2},
 | 
			
		||||
        yAxisRange: { min: 0, max: 1, interval: 0.2 }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@
 | 
			
		|||
      <TimeAxis
 | 
			
		||||
        v-if="timeList.length"
 | 
			
		||||
        :time-list="timeList"
 | 
			
		||||
        :is-auto-play="false"
 | 
			
		||||
        :is-auto-play="true"
 | 
			
		||||
        :start-time="new Date(timeList[0])"
 | 
			
		||||
        :end-time="new Date(timeList[timeList.length - 1])"
 | 
			
		||||
        @click:pointerDown="handlePointerDown"
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +21,6 @@ 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({
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +44,7 @@ const defaultConfig = {
 | 
			
		|||
    },
 | 
			
		||||
    shape: "circle",
 | 
			
		||||
    size: 30,
 | 
			
		||||
    color: "120,120,240",
 | 
			
		||||
    color: (node) => colorMap[node.cluster],
 | 
			
		||||
    borderColor: "200,50,50",
 | 
			
		||||
    borderWidth: 0,
 | 
			
		||||
    selected: {
 | 
			
		||||
| 
						 | 
				
			
			@ -129,73 +128,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 //记录上一次的长度
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,10 +20,10 @@
 | 
			
		|||
      </div>
 | 
			
		||||
      <div class="middle-container">
 | 
			
		||||
        <div class="graph">
 | 
			
		||||
          <!-- <GroupGraph
 | 
			
		||||
          <GroupGraph
 | 
			
		||||
            :store="groupStructureStore"
 | 
			
		||||
            @click:pointerDownAndSLide="handleChangeXAxis"
 | 
			
		||||
          ></GroupGraph> -->
 | 
			
		||||
          ></GroupGraph>
 | 
			
		||||
        </div>
 | 
			
		||||
        <!-- 事件脉络分析 -->
 | 
			
		||||
        <div class="postList">
 | 
			
		||||
| 
						 | 
				
			
			@ -74,45 +74,40 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import { ref, onMounted } from "vue";
 | 
			
		||||
import GroupPanel from "./components/groupPanel.vue";
 | 
			
		||||
import GroupGraph from "../component/groupGraph.vue";
 | 
			
		||||
import GroupChart from "../component/groupChart.vue";
 | 
			
		||||
import GroupPost from "../component/groupPost.vue";
 | 
			
		||||
import GroupAnalysis from "./components/groupAnalysis.vue";
 | 
			
		||||
import WordsCloud from "../component/wordsCloud.vue";
 | 
			
		||||
import userPanelTitleImg from "@/assets/images/groupEvolution/structure-panel-title.png";
 | 
			
		||||
import userChartTitleImg from "@/assets/images/groupEvolution/connectivity-title.png";
 | 
			
		||||
import groupAnalsisTitleImg from "@/assets/images/groupEvolution/structure-analysis-title.png";
 | 
			
		||||
import { Icon } from "@iconify/vue";
 | 
			
		||||
import { useGroupStructureStore } from "@/store/groupEvolution/index";
 | 
			
		||||
import { ref, onMounted } from "vue"
 | 
			
		||||
import GroupPanel from "./components/groupPanel.vue"
 | 
			
		||||
import GroupGraph from "../component/groupGraph.vue"
 | 
			
		||||
import GroupChart from "../component/groupChart.vue"
 | 
			
		||||
import GroupPost from "../component/groupPost.vue"
 | 
			
		||||
import GroupAnalysis from "./components/groupAnalysis.vue"
 | 
			
		||||
import WordsCloud from "../component/wordsCloud.vue"
 | 
			
		||||
import userPanelTitleImg from "@/assets/images/groupEvolution/structure-panel-title.png"
 | 
			
		||||
import userChartTitleImg from "@/assets/images/groupEvolution/connectivity-title.png"
 | 
			
		||||
import groupAnalsisTitleImg from "@/assets/images/groupEvolution/structure-analysis-title.png"
 | 
			
		||||
import { Icon } from "@iconify/vue"
 | 
			
		||||
import { useGroupStructureStore } from "@/store/groupEvolution/index"
 | 
			
		||||
 | 
			
		||||
const groupStructureStore = useGroupStructureStore();
 | 
			
		||||
const groupStructureStore = useGroupStructureStore()
 | 
			
		||||
 | 
			
		||||
const moduleName = '群体结构演化分析';
 | 
			
		||||
const moduleName = "群体结构演化分析"
 | 
			
		||||
 | 
			
		||||
//控制弹窗
 | 
			
		||||
const postDialog = ref(false);
 | 
			
		||||
const postDialog = ref(false)
 | 
			
		||||
 | 
			
		||||
//当前选中的贴文数据
 | 
			
		||||
const currentPostPost = ref(null);
 | 
			
		||||
 | 
			
		||||
const handleChangeXAxis = (utcTime) => {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
const currentPostPost = ref(null)
 | 
			
		||||
 | 
			
		||||
const handleChangeXAxis = (utcTime) => {}
 | 
			
		||||
 | 
			
		||||
const handleOpenPostDialog = (post) => {
 | 
			
		||||
  postDialog.value = true;
 | 
			
		||||
  currentPostPost.value = post;
 | 
			
		||||
  console.log(currentPostPost.value);
 | 
			
		||||
};
 | 
			
		||||
  postDialog.value = true
 | 
			
		||||
  currentPostPost.value = post
 | 
			
		||||
  console.log(currentPostPost.value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
  await groupStructureStore.initializeStructuralEvolutionChart()
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="less">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user