群体演化分析关系图组件封装完毕
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