diff --git a/src/views/LinkPrediction/socialGroups/components/communityNode.vue b/src/views/LinkPrediction/socialGroups/components/communityNode.vue
index 490ba26..0a1d8c4 100644
--- a/src/views/LinkPrediction/socialGroups/components/communityNode.vue
+++ b/src/views/LinkPrediction/socialGroups/components/communityNode.vue
@@ -17,6 +17,7 @@ import * as echarts from "echarts"
import nodeHoverImg from "@/assets/images/nodeHover.png"
let chart = null
+let linkList = null
const emit = defineEmits(["click:node", "click:edge"])
const statisticsList = inject("statisticsList");
const communityNodeList = inject("communityNodeList");
@@ -49,16 +50,16 @@ const initChart = async () => {
target: communityNei.id,
edge: communityNei.isHidden ? 1 : 0, //该边存在互动隐关系则权值为1,否则为0
lineStyle: {
- width: communityNei.isHidden ? 4 : 1, // 无互动=细线,有互动=加粗
+ width: communityNei.isHidden ? 7 : 1, // 无互动=细线,有互动=加粗
color: communityNei.isHidden ? "#FF5E00" : "#37ACD7", // 无互动=灰色,有互动=黄色
type: communityNei.isHidden ? "dashed" : "solid", // 无互动=实线,有互动=虚线
- dashArray: [2, 1] // 2像素实线,1像素空白
+ opacity: communityNei.isHidden ? 1 : 0.5,
}
})
edgeSet.add(key)
})
})
-
+ linkList = links
const data = { nodes, links }
const categories = [
@@ -241,7 +242,36 @@ const handleClickNode = () => {
} else if (params.dataType == "edge") {
const { data } = params
if (data.edge) {
- emit("click:edge", data)
+ const clickEdgeTarget = data.target
+ const clickEdgeSource = data.source
+ console.log("linkList", linkList)
+ // 找所有的虚线边
+ const dashedEdgeList = linkList.filter((item) => {
+ return item.lineStyle.type === "dashed"
+ })
+ console.log("dashedEdgeList", dashedEdgeList)
+ // 从所有的虚线边中找到连接了clickEdgeTarget或者clickEdgeSource的边
+ const connectEdgeList = dashedEdgeList.filter((item) => {
+ return item.source === clickEdgeSource
+ || item.target === clickEdgeTarget
+ || item.source === clickEdgeTarget
+ || item.target === clickEdgeSource
+ })
+ console.log("connectEdgeList", connectEdgeList)
+ let groupIdList = []
+ // 遍历边的source和target,找到所有的groupId
+ connectEdgeList.forEach((item) => {
+ if(!groupIdList.includes(item.source)) {
+ groupIdList.push(item.source)
+ }
+ if(!groupIdList.includes(item.target)) {
+ groupIdList.push(item.target)
+ }
+ })
+ // 只取前三个值
+ groupIdList = groupIdList.slice(0, 3)
+ console.log("打印点击边时,与目标节点和源节点相连的其他节点id",groupIdList);
+ emit("click:edge", data, groupIdList)
}
}
})
diff --git a/src/views/LinkPrediction/socialGroups/components/detailNode.vue b/src/views/LinkPrediction/socialGroups/components/detailNode.vue
index 46720b2..3368326 100644
--- a/src/views/LinkPrediction/socialGroups/components/detailNode.vue
+++ b/src/views/LinkPrediction/socialGroups/components/detailNode.vue
@@ -31,16 +31,20 @@
>
-
+
+
+
+
+
+
{{ TansTimestamp(endTime, "YYYY.MM.DD HH:mm:ss") }}
@@ -61,6 +65,21 @@ const socialGroupsStore = useSocialGroupsStore()
const { communityDetailNodeList } = storeToRefs(socialGroupsStore)
const { timeList } = storeToRefs(socialGroupsStore)
const { curHighlightUserIdList } = storeToRefs(socialGroupsStore)
+// 添加对curSelecedGroupIds的监听,用于检测列表项切换
+const { curSelecedGroupIds } = storeToRefs(socialGroupsStore)
+
+
+// 添加对curSelecedGroupIds的watch,确保切换列表项时重置时间轴
+watch(curSelecedGroupIds, (newIds) => {
+ if (newIds && newIds.length > 0) {
+ // 重置时间轴位置到起点
+ currentPosition.value = 0;
+ currentTime.value = new Date("2024-05-16 16:56:04");
+ // 重新开始自动播放
+ pause(); // 先停止可能正在运行的计时器
+ play(); // 重新开始播放
+ }
+}, { deep: true })
// 用于监听是从 列表 点进来的还是从 边 点进来的
const { clickEvent } = storeToRefs(socialGroupsStore)
@@ -68,6 +87,7 @@ const chartsData = ref({})
const emit = defineEmits(["click:goback"])
const handleGoback = () => {
+ pause()
emit("click:goback", "CommunityNode")
}
@@ -100,6 +120,48 @@ const startTime = ref(new Date("2024-05-16 16:56:04"))
const endTime = ref(new Date("2024-05-23 10:16:56"))
const currentTime = ref(new Date("2024-05-16 16:56:04")) // 当前选中的时间
const currentPosition = ref(0) // 初始位置(轴长度的一半)
+const lastPosition = ref(0) // 时间列表最后的时间点的位置
+const isPlaying = ref(false) // 是否自动播放
+let playTimer = null
+
+// 自动播放控制
+const play = () => {
+ if (isPlaying.value) return
+ isPlaying.value = true
+ playTimer = setInterval(() => {
+ // 步进像素
+ const step = 4 // 每次移动4px,可根据需要调整速度
+ if (currentPosition.value >= axisWidth) {
+ pause()
+ return
+ }
+ currentPosition.value = Math.min(axisWidth, currentPosition.value + step)
+ currentTime.value = getTimeFromPosition(currentPosition.value)
+ sendTimeChangeRequest()
+ }, 300) // 每300ms移动一次
+}
+
+// 发送请求逻辑封装
+const sendTimeChangeRequest = () => {
+ const currentTimes = TansTimestamp(currentTime.value, "YYYY-MM-DD HH:mm:ss")
+ if (socialGroupsStore.curRelationId == "") {
+ socialGroupsStore.initGraphCommunityDetailNode(socialGroupsStore.curSelecedGroupIds, currentTimes)
+ } else {
+ socialGroupsStore.initGraphCommunityDetailNode(
+ socialGroupsStore.curSelecedGroupIds,
+ currentTimes,
+ socialGroupsStore.curRelationId
+ )
+ }
+}
+
+const pause = () => {
+ isPlaying.value = false
+ if (playTimer) {
+ clearInterval(playTimer)
+ playTimer = null
+ }
+}
const axisRef = ref(null)
const isDragging = ref(false)
@@ -132,18 +194,16 @@ watch(timeList, (newList) => {
// watch来监听timeList变化并设置初始值
watch(timePointsWithPositions, (newTimePoints) => {
if (newTimePoints && newTimePoints.length > 0) {
- const lastTimePoint = newTimePoints[newTimePoints.length - 1]
- currentTime.value = lastTimePoint.time
- currentPosition.value = lastTimePoint.position
+ // 始终将currentPosition设置为0(时间轴起点)
+ currentPosition.value = 0;
+ currentTime.value = "2024-05-16 16:56:04"
+ lastPosition.value = newTimePoints[newTimePoints.length - 1].position
// 触发图更新
const currentTimes = TansTimestamp(currentTime.value, "YYYY-MM-DD HH:mm:ss")
+ socialGroupsStore.initGraphCommunityDetailNode(socialGroupsStore.curSelecedGroupIds, currentTimes)
}
}, { immediate: true })
-// 判断当前时间点是否激活
-/* const isTimeSignActive = (timeStr) => {
- return new Date(timeStr).getTime() === currentTime.value.getTime()
-} */
// 添加时间点点击事件处理函数
const handleTimePointClick = (timeStr) => {
@@ -167,6 +227,7 @@ const getTimeFromPosition = (position) => {
// 指针按下事件
const handlePointerDown = (e) => {
if (e.target.classList.contains("timeLine-point")) return
+ pause() // 拖动或点击时暂停自动播放
const rect = axisRef.value.getBoundingClientRect()
const position = Math.max(0, Math.min(axisWidth, e.clientX - rect.left))
@@ -247,6 +308,10 @@ const initChart = async () => {
else if (interactionTime > 30) return 10
else return 1
}
+ // 添加边唯一标识集合,用于检测重复边
+ const edgeSet = new Set()
+ // 使用Map存储边,方便后续查找和更新
+ const edgeMap = new Map()
if (!Object.keys(socialGroupsStore.communityDetailNodeList).length) return
// 先获取到所有节点
socialGroupsStore.communityAllNodeList.forEach((item) => {
@@ -260,17 +325,40 @@ const initChart = async () => {
})
Object.entries(socialGroupsStore.communityDetailNodeList).forEach(([parentId, children]) => {
children.forEach((child) => {
- links.push({
- source: parentId,
- target: child.id,
- edge: child.isHidden ? 1 : 0,
- interactionTimes: child.interactionTime,
- lineStyle: {
- width: child.isHidden ? 4 : edgeWidth(child.interactionTime),
- color: child.isHidden ? "#FF5E00" : "#37ACD7", // 无互动=灰色,有互动=黄色
- type: child.isHidden ? "dashed" : "solid" // 无互动=实线,有互动=虚线
+ // 生成边的唯一标识符,与方向无关
+ const edgeKey = [parentId, child.id].sort().join('-')
+ // 检查边是否已存在
+ if (!edgeSet.has(edgeKey)) {
+ edgeSet.add(edgeKey)
+ const newEdge = {
+ source: parentId,
+ target: child.id,
+ edge: child.isHidden ? 1 : 0,
+ interactionTimes: child.interactionTime,
+ lineStyle: {
+ width: child.isHidden ? 7 : edgeWidth(child.interactionTime),
+ color: child.isHidden ? "#FF5E00" : "#37ACD7", // 无互动=橙色,有互动=蓝色
+ type: child.isHidden ? "dashed" : "solid", // 无互动=虚线,有互动=实线
+ opacity: child.isHidden ? 1 : 0.5,
+ }
}
- })
+ links.push(newEdge)
+ edgeMap.set(edgeKey, newEdge)
+ } else {
+ // 边已存在,检查isHidden状态是否变化
+ const existingEdge = edgeMap.get(edgeKey)
+ // 只在isHidden从false变为true时更新样式
+ if (!existingEdge.edge && child.isHidden) {
+ existingEdge.edge = 1
+ existingEdge.lineStyle = {
+ width: 7,
+ color: "#FF5E00",
+ type: "dashed",
+ opacity: 1
+ }
+ }
+ }
+
})
@@ -443,7 +531,7 @@ const initChart = async () => {
categories: categories,
force: {
edgeLength: 2500,
- repulsion: 4000,
+ repulsion: 20000,
gravity: 0.1,
friction: 0.02,
coolingFactor: 0.1
@@ -499,8 +587,6 @@ const highLightUserNodes = (newHiglightUserIdList) => {
//等待所有节点添加完毕后再查找
newHiglightUserIdList.forEach((id) => {
const index = chartsData.value.nodes.findIndex((node) => node.id === id)
- console.log(index);
-
if (index != -1) {
chart.dispatchAction({
type: "highlight",
@@ -520,6 +606,7 @@ onMounted(() => {
}, 0)
})
highLightUserNodes()
+ play()
})
@@ -642,52 +729,48 @@ onMounted(() => {
height: 30px;
background: transparent;
}
-
}
- .active-sign {
- position: relative;
+
+ .active-needle {
+ width: 30px;
+ height: 34px;
+ background-image: url("@/assets/images/point.png");
+ background-size: cover;
+ bottom: 1px;
+ left: -11px;
+ position: absolute;
+ }
+ .timeLine-point {
z-index: 2;
- .active-needle {
- width: 30px;
- height: 34px;
- background-image: url("@/assets/images/point.png");
- background-size: cover;
- bottom: 1px;
- left: -11px;
- position: absolute;
+ width: 18px;
+ height: 18px;
+ background-color: transparent;
+ border-radius: 50%;
+ border: 1.6px solid #ffe5a4;
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ top: -6px;
+ left: -5px;
+ cursor: pointer;
+ user-select: none;
+ will-change: left;
+ transform: translate3d(0, 0, 0); // 强制启用硬件加速
+ &:hover {
+ transform: translate3d(0, 0, 0) scale(1.1);
}
- .timeLine-point {
- width: 18px;
- height: 18px;
- background-color: transparent;
+ &:active {
+ transform: translate3d(0, 0, 0) scale(0.95);
+ }
+ &::after {
+ content: "";
+ width: 10px;
+ height: 10px;
+ background-color: #f9bd25;
border-radius: 50%;
- border: 1.6px solid #ffe5a4;
position: absolute;
- display: flex;
- align-items: center;
- justify-content: center;
- top: -6px;
- left: -5px;
- cursor: pointer;
- user-select: none;
- will-change: left;
- transform: translate3d(0, 0, 0); // 强制启用硬件加速
- &:hover {
- transform: translate3d(0, 0, 0) scale(1.1);
- }
- &:active {
- transform: translate3d(0, 0, 0) scale(0.95);
- }
- &::after {
- content: "";
- width: 10px;
- height: 10px;
- background-color: #f9bd25;
- border-radius: 50%;
- position: absolute;
- }
}
-
}
}
.current-time-display {
diff --git a/src/views/LinkPrediction/socialGroups/components/graph.vue b/src/views/LinkPrediction/socialGroups/components/graph.vue
index 8cfa4e6..4f85ccd 100644
--- a/src/views/LinkPrediction/socialGroups/components/graph.vue
+++ b/src/views/LinkPrediction/socialGroups/components/graph.vue
@@ -34,15 +34,17 @@ const handleClickNode = async (nodeInfo) => {
socialGroupsStore.curRelationId = ""
}
-const handleClickEdge = async (edgeInfo) => {
+const handleClickEdge = async (edgeInfo, groupIdList) => {
console.log("点击边");
socialGroupsStore.curComponent = "detailNode"
socialGroupsStore.clickEvent = "edge"
socialGroupsStore.curRelationId = ""
// 先设置socialGroupsStore.clickEdgeTimeList
- await socialGroupsStore.getClickEdgeTimeList([edgeInfo.source, edgeInfo.target])
+ // await socialGroupsStore.getClickEdgeTimeList([edgeInfo.source, edgeInfo.target])
+ await socialGroupsStore.getClickEdgeTimeList(groupIdList)
const lastTime = socialGroupsStore.timeList[socialGroupsStore.timeList.length - 1]
- await socialGroupsStore.initGraphCommunityDetailNode([edgeInfo.source, edgeInfo.target], lastTime)
+ // await socialGroupsStore.initGraphCommunityDetailNode([edgeInfo.source, edgeInfo.target], lastTime)
+ await socialGroupsStore.initGraphCommunityDetailNode(groupIdList, lastTime)
}
diff --git a/src/views/LinkPrediction/socialGroups/components/userPanel.vue b/src/views/LinkPrediction/socialGroups/components/userPanel.vue
index 2438222..b60f49b 100644
--- a/src/views/LinkPrediction/socialGroups/components/userPanel.vue
+++ b/src/views/LinkPrediction/socialGroups/components/userPanel.vue
@@ -10,7 +10,7 @@
>
TOP{{ index+1 }}
diff --git a/src/views/LinkPrediction/socialGroups/index.vue b/src/views/LinkPrediction/socialGroups/index.vue
index 7725097..a281c6c 100644
--- a/src/views/LinkPrediction/socialGroups/index.vue
+++ b/src/views/LinkPrediction/socialGroups/index.vue
@@ -88,9 +88,7 @@ const handleSelectedUserGroup = (group) => {
console.log("点击列表group:",group)
const groupIds = group.list.map((item)=>item.groupId)
socialGroupsStore.curRelationId = group.relationId //保存当前点击的relationid,为了区分到底是从哪点进二级界面的
- const length = group.timeList.length
- const lastTime = group.timeList[length - 1]
- socialGroupsStore.initGraphCommunityDetailNode(groupIds, lastTime, group.relationId)
+ socialGroupsStore.initGraphCommunityDetailNode(groupIds, "2024-05-16 16:56:04", group.relationId)
socialGroupsStore.setTimeList(group.timeList)
socialGroupsStore.getSocialGroupPostListByRelationId(group.relationId)
};