From d3d57aa11d9ed4039ecc436604ade0d71286dde5 Mon Sep 17 00:00:00 2001 From: jzy <928294064@qq.com> Date: Sat, 27 Sep 2025 18:09:50 +0800 Subject: [PATCH 1/2] yangshi --- gyxtp/src/view/graphPageCopy0926.vue | 662 +++++++++++------------------------ 1 file changed, 200 insertions(+), 462 deletions(-) diff --git a/gyxtp/src/view/graphPageCopy0926.vue b/gyxtp/src/view/graphPageCopy0926.vue index 08e06a0..132c457 100644 --- a/gyxtp/src/view/graphPageCopy0926.vue +++ b/gyxtp/src/view/graphPageCopy0926.vue @@ -191,18 +191,54 @@ + +
+
+ +
+ +
展示层级{{i}}
+
+
+
+ +
-
+
+ > + + +
+
对这个节点进行操作:
+
查看节点
+
{{currentNode.expanded?'收回':'扩展'}}
+ +
+
@@ -261,6 +297,9 @@ export default { }, data() { return { + isShowCodePanel: false, + isShowNodeMenuPanel: false, + nodeMenuPanelPosition: { x: 0, y: 0 }, currentGroup:1, direction: "rtl", // visGraph实例对象 @@ -290,12 +329,6 @@ export default { data: [] //提示内部的数据 }, graphOptions: { - // 启用展开/折叠按钮 - defaultExpandHolderPosition: 'right', // 按钮显示位置:'left' 或 'right' - defaultExpandHolderSize: 16, - defaultExpandHolderColor: '#fff', - defaultExpandHolderBorder: '1px solid #00d7e0', - allowSwitchLineShape: true, allowSwitchJunctionPoint: true, defaultLineColor: '#2E74B5', @@ -317,14 +350,8 @@ export default { // 布局核心:使用 center 布局实现环形 layout: { layoutName: 'center', // 关键:使用 center 布局 - from: 'center', // 从中心向外扩展 - levelDistance: '3000,3000,3000,3000,3000,3000,3000,3000', // 每一层的半径(可动态修改) - nodeDistance: 10, // 同一层节点间的最小角度间距(影响密度) - min_per_width: 200, // 最小水平间隔(角度相关) - max_per_width: 100, - clockwise: true, // 是否顺时针排列 + levelDistance: '1000,1000,1000,1000,3000,3000,3000,3000', // 每一层的半径(可动态修改) startAngle: -Math.PI / 2, // 起始角度(-90°,顶部开始) - preventOverlap: true // 防止重叠 } }, currentNode: {}, // 选中的节点对象 @@ -400,22 +427,49 @@ export default { level: 'titleLevel', docLevel: 'docLevel', }, - heightlightTable:[] + heightlightTable:[], + currentShowLeve:1, } }, methods: { - changeGroup(groupId){ - this.currentGroup = groupId - this.getInfo() + showNodeMenus(nodeObject, $event) { + this.currentNode = nodeObject; + const _base_position = this.$refs.myPage.getBoundingClientRect(); + this.isShowNodeMenuPanel = true; + this.nodeMenuPanelPosition.x = $event.clientX - _base_position.x; + this.nodeMenuPanelPosition.y = $event.clientY - _base_position.y; }, - onNodeCollapse(node, e) { - this.$refs.graphRef.refresh(); + showOrHide(){ + this.currentNode.expanded = !this.currentNode.expanded + const graphInstance = this.$refs.graphRef.getInstance(); + graphInstance.doLayout() }, + toNodeInfo() { + let nodeObject = this.currentNode + console.log(nodeObject) + const data = { + 'id': nodeObject.data.docId, + 'docTitle': nodeObject.text, + } + getDocInfo(data).then((res) => { + localStorage.setItem("docUrl", res.data.docUrl) + this.$router.push({ + name: 'docInfo', + query: { + title: res.data.docTitle, + level: res.data.docLevel, + keyword: res.data.docTitle, + docId: res.data.id + } + }) + }); - // 节点展开时触发 - onNodeExpand(node, e) { - this.$refs.graphRef.refresh(); + this.isShowNodeMenuPanel = false; + }, + changeGroup(groupId){ + this.currentGroup = groupId + this.getInfo() }, handleNodeClick(node) { console.log(node); @@ -636,10 +690,10 @@ export default { const nodes = this.heightLight.nodes; const nodes1 = this.heightLight.nodes1; if (nodes==undefined){ - return ""; + return "nodeclassnormal"; } if (nodes.length === 0&&nodes1.length === 0) { - return ""; + return "nodeclassnormal"; } // 将传入的 id 转为字符串 const targetId = String(name).trim(); @@ -657,10 +711,9 @@ export default { found = found || found2 // 找到了返回 'nodeclass',否则返回 '' - return found ? 'nodeclass' : ''; + return found ? 'nodeclass' : 'nodeclassnormal'; }, getLinesClass(mergedDbIds) { - console.log("44444444444444") const lines = this.heightLight.links; if (lines == undefined){ return "" @@ -722,9 +775,46 @@ export default { // line.sourceAsMap.data this.drawer = true; }, - //整理图谱数据 - //整理图谱数据 - //整理图谱数据 + getNodeColor(leve){ + let color = "" + switch (leve) { + case "0": + color = '#ffd602'; + break; + case "1": + color = 'rgb(64, 158, 255)'; + break; + case "2": + color = '#ff8c00'; + break; + case "3": + color = '#67c23a'; + break; + case "4": + color = 'rgb(248,143,248)'; + break; + case "5": + color = 'rgb(65,154,255)'; + break; + case "6": + color = 'rgb(0,228,255)'; + break; + default: + color = 'rgba(255, 255, 255, 0.6)'; + } + console.log(color) + return color; + }, + getExpanded(leve){ + if (leve { - nodeMap[node.id] = node; - }); - // 找出有连接的节点 const connectedNodeIds = new Set(); lineList.forEach(line => { @@ -745,421 +829,74 @@ export default { connectedNodeIds.add(line.target); }); - // 按层级和组别分组孤立节点 - const isolatedNodesByGroupAndLevel = {}; - nodeList.forEach(node => { - if (!connectedNodeIds.has(node.id)) { - const groupId = node.groupId || '1'; - const level = node.docLeve || '0'; - if (!isolatedNodesByGroupAndLevel[groupId]) { - isolatedNodesByGroupAndLevel[groupId] = {}; + + // 在遍历前先按 docLeve 分组统计数量 + const nodesByLevel = {}; + for (let i = 0; i < nodeList.length; i++) { + const node = nodeList[i]; + if (node.groupId == this.currentGroup || node.docLeve == "0") { + // 仅孤立节点判断,超出层级不展示 + if (Number(node.docLeve) > this.currentShowLeve) { + if (!connectedNodeIds.has(node.id)) { + continue; + } } - if (!isolatedNodesByGroupAndLevel[groupId][level]) { - isolatedNodesByGroupAndLevel[groupId][level] = []; + + const level = Number(node.docLeve); + if (!nodesByLevel[level]) { + nodesByLevel[level] = []; } - isolatedNodesByGroupAndLevel[groupId][level].push(node); + nodesByLevel[level].push(node); } - }); + } - // 存储每个层级每个组别的节点位置信息 - const levelGroupPositions = {}; - - // 处理有连接的节点 - if (nodeList != undefined) { - // 按组别分组处理有连接的节点 - const groupedNodes = { - '0': {levels: {}}, - '1': {levels: {}}, - '2': {levels: {}} - }; - - // 按组别和层级分类节点 - nodeList.forEach(node => { - if (connectedNodeIds.has(node.id)) { - const groupId = node.groupId || '1'; - const level = node.docLeve || '1'; - if (!groupedNodes[groupId]) groupedNodes[groupId] = {levels: {}}; - if (!groupedNodes[groupId].levels[level]) groupedNodes[groupId].levels[level] = []; - groupedNodes[groupId].levels[level].push(node); - } - }); +// 配置参数 + const baseRadius = 1200; // 每层之间的半径差 + const centerX = 0, centerY = 0; - // 定义组别的位置偏移 - const groupOffsets = { - '0': -10200, // 左侧区域 - '1': 0, // 中间区域 - '2': 10200 // 右侧区域 - }; - - // 处理每个组别的节点 - Object.keys(groupedNodes).forEach(groupId => { - const groupData = groupedNodes[groupId]; - const groupOffsetX = groupOffsets[groupId] || 0; - - // 处理每个层级的节点 - Object.keys(groupData.levels).sort().forEach(level => { - const levelNodes = groupData.levels[level].sort((a, b) => a.docId - b.docId); - const levelNum = parseInt(level); - - // 计算该层级节点的起始X位置(考虑组别偏移) - const startX = groupOffsetX - (levelNodes.length * 200) / 2; - - // 初始化该层级该组别的位置信息 - const levelGroupKey = `${levelNum}_${groupId}`; - if (!levelGroupPositions[levelGroupKey]) { - levelGroupPositions[levelGroupKey] = { - minX: startX, - maxX: startX + levelNodes.length * 200, - leftAvailableX: startX - 200, // 左侧可用位置 - rightAvailableX: startX + 200, // 右侧可用位置 - hasConnectedNodes: levelNodes.length > 0 - }; - } +// 遍历每一层进行布局 + Object.keys(nodesByLevel).forEach(levelStr => { + const level = Number(levelStr); + const levelNodes = nodesByLevel[level]; + const total = levelNodes.length; + const radius = level === 0 ? 0 : level * baseRadius; // level 0 放中心 - levelNodes.forEach((node, index) => { - if (levelNum === 0) this.rootId = node.id; - - // 根据层级设置节点样式 - let color, fontSize, fontColor; - switch (levelNum) { - case 0: - color = 'rgb(227,203,0)'; - fontSize = '200px'; - fontColor = 'rgb(255,255,255)'; - break; - case 1: - color = 'rgb(47,47,230)'; - fontSize = '200px'; - fontColor = 'rgb(255,255,255)'; - break; - case 2: - color = 'rgb(255,138,0)'; - fontSize = '200px'; - fontColor = 'rgb(255,255,255)'; - break; - case 3: - color = 'rgb(30,255,0)'; - fontSize = '200px'; - fontColor = 'rgb(0,0,0)'; - break; - case 4: - color = 'rgb(248,143,248)'; - fontSize = '200px'; - fontColor = 'rgb(255,255,255)'; - break; - case 5: - color = 'rgb(65,154,255)'; - fontSize = '200px'; - fontColor = 'rgb(255,255,255)'; - break; - case 6: - color = 'rgb(0,228,255)'; - fontSize = '200px'; - fontColor = 'rgb(0,0,0)'; - break; - default: - color = 'rgb(200,200,200)'; - fontSize = '200px'; - fontColor = 'rgb(255,255,255)'; - } - - const x = startX + index * 200; - // 修改点:当 groupId 为 '1' 时,Y 值反向 - const y = groupId === '1' ? levelNum * -1400 : levelNum * 1400; - - - if (node.groupId==this.currentGroup || node.docLeve=="0"){ - // 添加节点 - nodes.push({ - id: node.id, - text: node.name, - data: { - docId: node.docId, - group: node.groupId - }, - level: levelNum, - // x: x, - // y: y, - // fixed: true, - width: 150, - height: 150, - color: color, - font: `normal ${fontSize} Arial`, - fontColor: fontColor, - expandHolderPosition: 'right', - expanded: true, - styleClass:this.getNodeClass(node.name), - }); - } - - }); + levelNodes.forEach((node, index) => { + let x, y; + + if (level === 0) { + // 中心节点放在原点 + x = 0; + y = 0; + } else { + // 计算极角 + const angle = (2 * Math.PI / total) * index; // 均匀分布 + x = centerX + radius * Math.cos(angle); + y = centerY + radius * Math.sin(angle); + } + + nodes.push({ + id: node.id, + text: node.name, + data: { + docId: node.docId, + group: node.groupId + }, + level: node.docLeve, + x: x, + y: y, + fixed: true, // 锁定位置 + width: 250, + height: 250, + color: this.getNodeColor(node.docLeve), + expandHolderPosition: 'right', + expanded: this.getExpanded(node.docLeve), + styleClass: this.getNodeClass(node.name), }); }); - } + }); + - // 处理孤立节点 - 放置在有连线节点的两侧 - // Object.keys(isolatedNodesByGroupAndLevel).sort().forEach(groupId => { - // const groupData = isolatedNodesByGroupAndLevel[groupId]; - // const groupOffsetX = groupId === '0' ? -10200 : groupId === '1' ? 0 : 10200; - // - // Object.keys(groupData).sort().forEach(level => { - // const levelNodes = groupData[level]; - // const levelNum = parseInt(level); - // - // // 确定孤立节点的Y坐标(与有连接节点保持一致) - // const y = groupId === '1' ? levelNum * -1400 : levelNum * 1400; - // - // // 获取或创建该层级该组别的位置信息 - // const levelGroupKey = `${levelNum}_${groupId}`; - // - // // 先按docId排序孤立节点 - // const sortedIsolatedNodes = levelNodes.sort((a, b) => a.docId - b.docId); - // - // if (!levelGroupPositions[levelGroupKey] || !levelGroupPositions[levelGroupKey].hasConnectedNodes) { - // // 如果没有有连接的节点,居中展示孤立节点 - // const totalWidth = sortedIsolatedNodes.length * 200; - // const startX = groupOffsetX - totalWidth / 2; - // - // // 放置孤立节点(居中排列) - // sortedIsolatedNodes.forEach((node, index) => { - // // 根据层级设置节点样式 - // let color, fontSize, fontColor; - // switch (levelNum) { - // case 0: - // color = 'rgb(227,203,0)'; - // fontSize = '70px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 1: - // color = 'rgb(47,47,230)'; - // fontSize = '68px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 2: - // color = 'rgb(255,138,0)'; - // fontSize = '50px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 3: - // color = 'rgb(30,255,0)'; - // fontSize = '40px'; - // fontColor = 'rgb(0,0,0)'; - // break; - // case 4: - // color = 'rgb(248,143,248)'; - // fontSize = '32px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 5: - // color = 'rgb(65,154,255)'; - // fontSize = '30px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 6: - // color = 'rgb(0,228,255)'; - // fontSize = '28px'; - // fontColor = 'rgb(0,0,0)'; - // break; - // default: - // color = 'rgb(200,200,200)'; - // fontSize = '24px'; - // fontColor = 'rgb(255,255,255)'; - // } - // - // const x = startX + index * 200; - // - // if (node.groupId==this.currentGroup || node.docLeve=="0"){ - // // 添加节点 - // nodes.push({ - // id: node.id, - // text: node.name, - // data: { - // docId: node.docId, - // group: node.groupId - // }, - // level: levelNum, - // // x: x, - // // y: y, - // // fixed: true, - // width: 150, - // height: 150, - // color: color, - // font: `normal ${fontSize} Arial`, - // fontColor: fontColor, - // expandHolderPosition: 'right', - // expanded: true, - // styleClass:this.getNodeClass(node.name), - // }); - // } - // }); - // } else { - // // 如果有有连接的节点,在两侧放置孤立节点 - // const positionInfo = levelGroupPositions[levelGroupKey]; - // - // // 将孤立节点分成两组:左侧和右侧 - // const leftNodes = []; - // const rightNodes = []; - // - // sortedIsolatedNodes.forEach((node, index) => { - // if (index % 2 === 0) { - // leftNodes.push(node); // 偶数索引放左侧 - // } else { - // rightNodes.push(node); // 奇数索引放右侧 - // } - // }); - // - // // 放置左侧孤立节点(从右往左排列) - // let currentLeftX = positionInfo.leftAvailableX; - // for (let i = leftNodes.length - 1; i >= 0; i--) { - // const node = leftNodes[i]; - // - // // 根据层级设置节点样式 - // let color, fontSize, fontColor; - // switch (levelNum) { - // case 0: - // color = 'rgb(227,203,0)'; - // fontSize = '70px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 1: - // color = 'rgb(47,47,230)'; - // fontSize = '68px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 2: - // color = 'rgb(255,138,0)'; - // fontSize = '50px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 3: - // color = 'rgb(30,255,0)'; - // fontSize = '40px'; - // fontColor = 'rgb(0,0,0)'; - // break; - // case 4: - // color = 'rgb(248,143,248)'; - // fontSize = '32px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 5: - // color = 'rgb(65,154,255)'; - // fontSize = '30px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 6: - // color = 'rgb(0,228,255)'; - // fontSize = '28px'; - // fontColor = 'rgb(0,0,0)'; - // break; - // default: - // color = 'rgb(200,200,200)'; - // fontSize = '24px'; - // fontColor = 'rgb(255,255,255)'; - // } - // - // if (node.groupId==this.currentGroup || node.docLeve=="0"){ - // // 添加节点 - // nodes.push({ - // id: node.id, - // text: node.name, - // data: { - // docId: node.docId, - // group: node.groupId - // }, - // level: levelNum, - // // x: x, - // // y: y, - // // fixed: true, - // width: 150, - // height: 150, - // color: color, - // font: `normal ${fontSize} Arial`, - // fontColor: fontColor, - // expandHolderPosition: 'right', - // expanded: true, - // styleClass:this.getNodeClass(node.name), - // }); - // } - // - // currentLeftX -= 200; - // } - // - // // 放置右侧孤立节点(从左往右排列) - // let currentRightX = positionInfo.rightAvailableX; - // rightNodes.forEach(node => { - // // 根据层级设置节点样式 - // let color, fontSize, fontColor; - // switch (levelNum) { - // case 0: - // color = 'rgb(227,203,0)'; - // fontSize = '70px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 1: - // color = 'rgb(47,47,230)'; - // fontSize = '68px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 2: - // color = 'rgb(255,138,0)'; - // fontSize = '50px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 3: - // color = 'rgb(30,255,0)'; - // fontSize = '40px'; - // fontColor = 'rgb(0,0,0)'; - // break; - // case 4: - // color = 'rgb(248,143,248)'; - // fontSize = '32px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 5: - // color = 'rgb(65,154,255)'; - // fontSize = '30px'; - // fontColor = 'rgb(255,255,255)'; - // break; - // case 6: - // color = 'rgb(0,228,255)'; - // fontSize = '28px'; - // fontColor = 'rgb(0,0,0)'; - // break; - // default: - // color = 'rgb(200,200,200)'; - // fontSize = '24px'; - // fontColor = 'rgb(255,255,255)'; - // } - // - // if (node.groupId==this.currentGroup || node.docLeve=="0"){ - // // 添加节点 - // nodes.push({ - // id: node.id, - // text: node.name, - // data: { - // docId: node.docId, - // group: node.groupId - // }, - // level: levelNum, - // // x: x, - // // y: y, - // // fixed: true, - // width: 150, - // height: 150, - // color: color, - // font: `normal ${fontSize} Arial`, - // fontColor: fontColor, - // expandHolderPosition: 'right', - // expanded: true, - // styleClass:this.getNodeClass(node.name), - // }); - // } - // - // currentRightX += 200; - // }); - // } - // }); - // }); // 处理连线 lineList.forEach(line => { @@ -1169,6 +906,9 @@ export default { style=this.getLinesClass(line.DbId) num=10 } + + // 查询父节点是否是展示状态 + links.push({ id:line.DbId, from: line.source, @@ -1210,23 +950,18 @@ export default { }) }, onNodeClick(nodeObject, $event) { - console.log(nodeObject) - const data = { - 'id': nodeObject.data.docId, - 'docTitle': nodeObject.text, + console.log(nodeObject.id) + const graphInstance = this.$refs.graphRef.getInstance(); + let node = graphInstance.getNodeById(nodeObject.id) + let relinks = graphInstance.getLinesByNode(node); + + for (let i=0;i { - localStorage.setItem("docUrl", res.data.docUrl) - this.$router.push({ - name: 'docInfo', - query: { - title: res.data.docTitle, - level: res.data.docLevel, - keyword: res.data.docTitle, - docId: res.data.id - } - }) - }); } }, created() { @@ -1846,7 +1581,7 @@ tr { stroke: white !important; stroke-width: 3 !important; stroke-opacity: 1 !important; - + font-size: 20px !important; /* 多层光晕:内层青色,外层白色 */ filter: drop-shadow(0 0 20px rgba(0, 255, 255, 1)) /* 内层青色光晕 */ @@ -1857,6 +1592,9 @@ tr { /* 确保边框在填充之上 */ paint-order: stroke fill !important; } +.nodeclassnormal{ + font-size: 20px !important; +} .el-table .warning-row { background: oldlace; } From c753001ec009ee9156cef7132191a03727752cc4 Mon Sep 17 00:00:00 2001 From: jzy <928294064@qq.com> Date: Sat, 27 Sep 2025 18:16:40 +0800 Subject: [PATCH 2/2] yangshi --- gyxtp/src/view/graphPageCopy0926.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gyxtp/src/view/graphPageCopy0926.vue b/gyxtp/src/view/graphPageCopy0926.vue index 132c457..8fbcc15 100644 --- a/gyxtp/src/view/graphPageCopy0926.vue +++ b/gyxtp/src/view/graphPageCopy0926.vue @@ -198,7 +198,7 @@ border-radius: 2px; padding: 5px 0; background-color: rgba(76,100,233,0.3) ;position:absolute;left: 5vw;top: 12vw;font-size: 0.9vw;overflow-y: scroll;margin-left: 1vw;margin-right: 1vw;"> -
+