社团紧密关系-点边
This commit is contained in:
parent
960130fba1
commit
2a15f5a5f9
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -31,16 +31,20 @@
|
|||
>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<div class="active-sign" :style="{ left: `${currentPosition}px` }">
|
||||
<div class="active-needle"></div>
|
||||
<el-tooltip
|
||||
:content="TansTimestamp(currentTime, 'YYYY.MM.DD HH:mm:ss')"
|
||||
placement="bottom"
|
||||
effect="light"
|
||||
>
|
||||
<div class="timeLine-point" @pointerdown.stop="handlePointPointerDown"></div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-tooltip
|
||||
:content="TansTimestamp(timeList[timeList.length - 1], 'YYYY.MM.DD HH:mm:ss')"
|
||||
placement="bottom"
|
||||
effect="light"
|
||||
>
|
||||
<div class="active-needle" :style="{ left: `${lastPosition}px` }"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
:content="TansTimestamp(currentTime, 'YYYY.MM.DD HH:mm:ss')"
|
||||
placement="bottom"
|
||||
effect="light"
|
||||
>
|
||||
<div class="timeLine-point" :style="{ left: `${currentPosition}px` }" @pointerdown.stop="handlePointPointerDown"></div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="time">{{ TansTimestamp(endTime, "YYYY.MM.DD HH:mm:ss") }}</div>
|
||||
</div>
|
||||
|
|
@ -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()
|
||||
|
||||
})
|
||||
</script>
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
>
|
||||
<div class="group-type" v-if="group.list.length > 2 && group?.interactivity != ' '">
|
||||
<img
|
||||
src="@/assets/images/linkPrediction/title/group-item-title.png"
|
||||
src="@/assets/images/linkPrediction/icon/top-icon.png"
|
||||
class="group-type-back"
|
||||
/>
|
||||
<div class="group-type-content">TOP{{ index+1 }}</div>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user