群体演化分析关系图组件封装完毕
This commit is contained in:
parent
f24cce9202
commit
3c6a07f45c
|
|
@ -12,10 +12,7 @@ import {
|
||||||
getGroupEvolutionGroupScaleChart,
|
getGroupEvolutionGroupScaleChart,
|
||||||
getGroupEvolutionTimeLine,
|
getGroupEvolutionTimeLine,
|
||||||
getPostByUtcTime,
|
getPostByUtcTime,
|
||||||
|
|
||||||
getStructuralEvolutionChart,
|
getStructuralEvolutionChart,
|
||||||
|
|
||||||
|
|
||||||
getGroupMemberInfoList,
|
getGroupMemberInfoList,
|
||||||
getGroupMemberTimeLine,
|
getGroupMemberTimeLine,
|
||||||
getGroupMemberChart,
|
getGroupMemberChart,
|
||||||
|
|
@ -240,8 +237,7 @@ export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
|
||||||
return {
|
return {
|
||||||
id: node.name,
|
id: node.name,
|
||||||
label: node.name,
|
label: node.name,
|
||||||
color: setColor(node.groupId),
|
type: node.groupId
|
||||||
cluster: parseInt(node.groupId)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
@ -265,21 +261,21 @@ export const useGroupStructureStore = defineStore("groupStructure", {
|
||||||
type: "群体一",
|
type: "群体一",
|
||||||
focusedTopic: "#中国海警首次登检菲律宾运补船只",
|
focusedTopic: "#中国海警首次登检菲律宾运补船只",
|
||||||
innerNum: 20,
|
innerNum: 20,
|
||||||
outerNum: 100,
|
outerNum: 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
type: "群体二",
|
type: "群体二",
|
||||||
focusedTopic: "#外交部回应中国海警缴获菲土乓枪支",
|
focusedTopic: "#外交部回应中国海警缴获菲土乓枪支",
|
||||||
innerNum: 20,
|
innerNum: 20,
|
||||||
outerNum: 100,
|
outerNum: 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
type: "群体三",
|
type: "群体三",
|
||||||
focusedTopic: "#社会群体对中国海警缴获菲土乓枪支",
|
focusedTopic: "#社会群体对中国海警缴获菲土乓枪支",
|
||||||
innerNum: 20,
|
innerNum: 20,
|
||||||
outerNum: 100,
|
outerNum: 100
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
chartData: {
|
chartData: {
|
||||||
|
|
@ -290,7 +286,7 @@ export const useGroupStructureStore = defineStore("groupStructure", {
|
||||||
data: [0.3055, 0.3939, 0.5813, 0.6094, 0.6289],
|
data: [0.3055, 0.3939, 0.5813, 0.6094, 0.6289],
|
||||||
name: "",
|
name: "",
|
||||||
themeColor: "#2AB8FD"
|
themeColor: "#2AB8FD"
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
chartsData: {
|
chartsData: {
|
||||||
|
|
@ -541,7 +537,7 @@ export const useGroupStructureStore = defineStore("groupStructure", {
|
||||||
async initializeStructuralEvolutionChart() {
|
async initializeStructuralEvolutionChart() {
|
||||||
const res = await getStructuralEvolutionChart()
|
const res = await getStructuralEvolutionChart()
|
||||||
this.chartData = {
|
this.chartData = {
|
||||||
xAxisData: res.data.xaxisData.map(item => utcStringToHHMMSS(item)),
|
xAxisData: res.data.xaxisData.map((item) => utcStringToHHMMSS(item)),
|
||||||
seriesList: [
|
seriesList: [
|
||||||
{
|
{
|
||||||
name: "",
|
name: "",
|
||||||
|
|
@ -549,7 +545,7 @@ export const useGroupStructureStore = defineStore("groupStructure", {
|
||||||
themeColor: "#2AB8FD"
|
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.drawOriginalLine(ctx, needHideText) //内置默认的绘制方法
|
||||||
|
|
||||||
//指定路径,用于鼠标检测选中
|
//指定路径,用于鼠标检测选中
|
||||||
// this.path = [
|
this.path = [
|
||||||
// { x: this.source.cx, y: this.source.cy },
|
{ x: this.source.cx, y: this.source.cy },
|
||||||
// { x: this.target.cx, y: this.target.cy }
|
{ x: this.target.cx, y: this.target.cy }
|
||||||
// ];
|
]
|
||||||
|
|
||||||
// //绘制路径
|
// //绘制路径
|
||||||
// ctx.beginPath();
|
ctx.beginPath()
|
||||||
// ctx.moveTo(this.source.cx,this.source.cy);
|
ctx.moveTo(this.source.cx, this.source.cy)
|
||||||
// ctx.lineTo(this.target.cx,this.target.cy);
|
ctx.lineTo(this.target.cx, this.target.cy)
|
||||||
// this.setLineStyle(ctx);
|
this.setLineStyle(ctx)
|
||||||
// ctx.stroke();
|
ctx.stroke()
|
||||||
|
|
||||||
// //绘制连线上文字(内部方法)
|
// //绘制连线上文字(内部方法)
|
||||||
// this.paintTextOnLineWithAngle(ctx, this.source, this.target);
|
this.paintTextOnLineWithAngle(ctx, this.source, this.target)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<TimeAxis
|
<TimeAxis
|
||||||
v-if="timeList.length"
|
v-if="timeList.length"
|
||||||
:time-list="timeList"
|
:time-list="timeList"
|
||||||
:is-auto-play="false"
|
:is-auto-play="true"
|
||||||
:start-time="new Date(timeList[0])"
|
:start-time="new Date(timeList[0])"
|
||||||
:end-time="new Date(timeList[timeList.length - 1])"
|
:end-time="new Date(timeList[timeList.length - 1])"
|
||||||
@click:pointerDown="handlePointerDown"
|
@click:pointerDown="handlePointerDown"
|
||||||
|
|
@ -21,7 +21,6 @@ import { defineProps, defineEmits, onUnmounted, ref, toRaw, watch } from "vue"
|
||||||
import { storeToRefs } from "pinia"
|
import { storeToRefs } from "pinia"
|
||||||
import { convertToUtcIsoString } from "@/utils/transform"
|
import { convertToUtcIsoString } from "@/utils/transform"
|
||||||
import { paintNodeFunction, paintLineFunction } from "@/utils/customePaint"
|
import { paintNodeFunction, paintLineFunction } from "@/utils/customePaint"
|
||||||
import { demoData } from "@/assets/customeGraph/data"
|
|
||||||
import TimeAxis from "@/components/timeAxis.vue"
|
import TimeAxis from "@/components/timeAxis.vue"
|
||||||
import GraphVis from "@/assets/package/graphvis.esm.min.js"
|
import GraphVis from "@/assets/package/graphvis.esm.min.js"
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|
@ -45,7 +44,7 @@ const defaultConfig = {
|
||||||
},
|
},
|
||||||
shape: "circle",
|
shape: "circle",
|
||||||
size: 30,
|
size: 30,
|
||||||
color: "120,120,240",
|
color: (node) => colorMap[node.cluster],
|
||||||
borderColor: "200,50,50",
|
borderColor: "200,50,50",
|
||||||
borderWidth: 0,
|
borderWidth: 0,
|
||||||
selected: {
|
selected: {
|
||||||
|
|
@ -129,56 +128,52 @@ const registEvents = () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const runForceLayout = () => {
|
const runForceLayout = () => {
|
||||||
let viewCenter = graphVis.getViewCenter()
|
const layoutConfig = { strength: -500, ajustCluster: true }
|
||||||
let simulation = graphVis.getSimulationLayout()
|
//执行异步布局计算
|
||||||
let curForceSimulator = simulation.forceSimulation()
|
graphVis.excuteWorkerLayout(
|
||||||
curForceSimulator
|
graphVis.getGraphData(),
|
||||||
.nodes(graphVis.nodes)
|
"simulation",
|
||||||
.force("center", simulation.forceCenter(viewCenter.x, viewCenter.y))
|
layoutConfig,
|
||||||
.force("charge", simulation.forceManyBody().strength(-550).theta(0.85)) // manyBodyReuse|forceManyBody .distanceMin(300).distanceMax(400).theta(0.9)
|
false,
|
||||||
.force("link", simulation.forceLink(graphVis.links).distance(120).strength(0.35)) //.distance(120).strength(0.15)
|
function () {
|
||||||
.force(
|
graphVis.zoomFit() //布局结束缩放居中
|
||||||
"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() // 刷新视图
|
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
curForceSimulator.on("end", () => {
|
|
||||||
curForceSimulator.alpha(0)
|
|
||||||
curForceSimulator.stop()
|
|
||||||
})
|
|
||||||
forceSimulator = curForceSimulator
|
|
||||||
}
|
}
|
||||||
// 添加更新图表的函数
|
// 根据节点的cluster属性进行分组
|
||||||
const updateChart = (newGraphData) => {
|
const clusterAnalyze = () => {
|
||||||
if (!graphVis) {
|
graphVis.removeAllGroup() // 清除原有分组
|
||||||
initChart()
|
// 创建cluster到nodes的映射
|
||||||
return
|
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)
|
||||||
graphVis.clearAll()
|
})
|
||||||
|
const colorMap = {
|
||||||
// 添加新数据
|
0: "50,141,120", // 绿色
|
||||||
graphVis.addGraph({ ...toRaw(newGraphData) })
|
1: "133,129,48", // 黄色
|
||||||
graphVis.autoGroupLayout(toRaw(newGraphData).nodes)
|
6: "12,112,144" // 蓝色
|
||||||
|
}
|
||||||
// 重新运行力导向布局
|
clusterNodesMap.forEach((nodes, cluster) => {
|
||||||
runForceLayout()
|
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 initChart = () => {
|
|
||||||
const createGraph = () => {
|
const createGraph = () => {
|
||||||
if (!graphVis) {
|
if (!graphVis) {
|
||||||
graphVis = new GraphVis({
|
graphVis = new GraphVis({
|
||||||
container: document.getElementById("container"),
|
container: document.getElementById("container"),
|
||||||
|
|
@ -188,14 +183,30 @@ const initChart = () => {
|
||||||
}
|
}
|
||||||
graphVis.setDragHideLine(false) //拖拽时隐藏连线
|
graphVis.setDragHideLine(false) //拖拽时隐藏连线
|
||||||
graphVis.setShowDetailScale(0.1) //展示细节的比例
|
graphVis.setShowDetailScale(0.1) //展示细节的比例
|
||||||
graphVis.setZoomRange(0.05, 5) //缩放区间
|
graphVis.setZoomRange(0.1, 5) //缩放区间
|
||||||
registCustomePaintFunc() //注册自定义绘图方法
|
registCustomePaintFunc() //注册自定义绘图方法
|
||||||
registEvents()
|
registEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initChart = () => {
|
||||||
createGraph()
|
createGraph()
|
||||||
graphVis.addGraph({ ...toRaw(graph.value) })
|
graphVis.addGraph({ ...toRaw(graph.value) })
|
||||||
runForceLayout()
|
runForceLayout()
|
||||||
|
clusterAnalyze()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加更新图表的函数
|
||||||
|
const updateChart = (newGraphData) => {
|
||||||
|
if (!graphVis) {
|
||||||
|
initChart()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
graphVis.clearAll()
|
||||||
|
graphVis.addGraph({ ...toRaw(newGraphData) })
|
||||||
|
graphVis.zoomFit()
|
||||||
|
// 重新运行力导向布局
|
||||||
|
runForceLayout()
|
||||||
|
clusterAnalyze()
|
||||||
}
|
}
|
||||||
|
|
||||||
let lastLength = 0 //记录上一次的长度
|
let lastLength = 0 //记录上一次的长度
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="middle-container">
|
<div class="middle-container">
|
||||||
<div class="graph">
|
<div class="graph">
|
||||||
<!-- <GroupGraph
|
<GroupGraph
|
||||||
:store="groupStructureStore"
|
:store="groupStructureStore"
|
||||||
@click:pointerDownAndSLide="handleChangeXAxis"
|
@click:pointerDownAndSLide="handleChangeXAxis"
|
||||||
></GroupGraph> -->
|
></GroupGraph>
|
||||||
</div>
|
</div>
|
||||||
<!-- 事件脉络分析 -->
|
<!-- 事件脉络分析 -->
|
||||||
<div class="postList">
|
<div class="postList">
|
||||||
|
|
@ -74,45 +74,40 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue"
|
||||||
import GroupPanel from "./components/groupPanel.vue";
|
import GroupPanel from "./components/groupPanel.vue"
|
||||||
import GroupGraph from "../component/groupGraph.vue";
|
import GroupGraph from "../component/groupGraph.vue"
|
||||||
import GroupChart from "../component/groupChart.vue";
|
import GroupChart from "../component/groupChart.vue"
|
||||||
import GroupPost from "../component/groupPost.vue";
|
import GroupPost from "../component/groupPost.vue"
|
||||||
import GroupAnalysis from "./components/groupAnalysis.vue";
|
import GroupAnalysis from "./components/groupAnalysis.vue"
|
||||||
import WordsCloud from "../component/wordsCloud.vue";
|
import WordsCloud from "../component/wordsCloud.vue"
|
||||||
import userPanelTitleImg from "@/assets/images/groupEvolution/structure-panel-title.png";
|
import userPanelTitleImg from "@/assets/images/groupEvolution/structure-panel-title.png"
|
||||||
import userChartTitleImg from "@/assets/images/groupEvolution/connectivity-title.png";
|
import userChartTitleImg from "@/assets/images/groupEvolution/connectivity-title.png"
|
||||||
import groupAnalsisTitleImg from "@/assets/images/groupEvolution/structure-analysis-title.png";
|
import groupAnalsisTitleImg from "@/assets/images/groupEvolution/structure-analysis-title.png"
|
||||||
import { Icon } from "@iconify/vue";
|
import { Icon } from "@iconify/vue"
|
||||||
import { useGroupStructureStore } from "@/store/groupEvolution/index";
|
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 currentPostPost = ref(null)
|
||||||
|
|
||||||
const handleChangeXAxis = (utcTime) => {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const handleChangeXAxis = (utcTime) => {}
|
||||||
|
|
||||||
const handleOpenPostDialog = (post) => {
|
const handleOpenPostDialog = (post) => {
|
||||||
postDialog.value = true;
|
postDialog.value = true
|
||||||
currentPostPost.value = post;
|
currentPostPost.value = post
|
||||||
console.log(currentPostPost.value);
|
console.log(currentPostPost.value)
|
||||||
};
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await groupStructureStore.initializeStructuralEvolutionChart()
|
await groupStructureStore.initializeStructuralEvolutionChart()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user