如何用JavaScript固定vis.js Network中Tooltip/Popup的位置?
如何在vis.js Network中设置固定位置的Tooltip/Popup
我太懂你的痛点了——默认的tooltip跟着鼠标乱跑,想复制里面的文本简直让人抓狂!别担心,咱们可以通过禁用默认tooltip,自己实现一个固定在节点/边中心的自定义tooltip,完美解决选中文本的问题。下面是具体的实现步骤和完整代码:
核心思路
- 关掉vis.js自带的tooltip,避免冲突
- 监听节点和边的悬停事件,精准获取它们的位置
- 创建一个支持文本选中的自定义tooltip,把它定位到目标元素的中心区域
- 监听鼠标移出或点击空白区域的事件,及时隐藏tooltip
完整代码示例
<!DOCTYPE html> <html> <head> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.2.0/vis.min.js"></script> <link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.2.0/vis.min.css" rel="stylesheet" type="text/css" /> <style type="text/css"> #mynetwork { position: relative; width: 600px; height: 400px; border: 1px solid lightgray; } /* 自定义tooltip样式 */ #custom-tooltip { position: absolute; background-color: #fff; border: 1px solid #ccc; border-radius: 4px; padding: 8px; font-size: 14px; pointer-events: auto; /* 关键!允许鼠标选中文本 */ z-index: 1000; display: none; /* 默认隐藏 */ box-shadow: 0 2px 5px rgba(0,0,0,0.1); } </style> </head> <body> <div id="mynetwork"></div> <!-- 自定义tooltip容器 --> <div id="custom-tooltip"></div> <script type="text/javascript"> // 创建节点数组 var nodes = new vis.DataSet([ {id: 1, label: 'Node 1', title: '这是Node 1的固定Tooltip,可复制!'}, {id: 2, label: 'Node 2', title: 'Node 2的内容也能轻松复制'}, {id: 3, label: 'Node 3', title: '我固定在节点中心哦'}, {id: 4, label: 'Node 4', title: '选我选我!'}, {id: 5, label: 'Node 5', title: '完美解决复制问题'} ]); // 创建边数组 var edges = new vis.DataSet([ {from: 1, to: 3, title: '边1-3的固定Tooltip'}, {from: 1, to: 2, title: '边1-2的内容'}, {from: 2, to: 4, title: '边2-4的文本可复制'}, {from: 2, to: 5, title: '我在边的中间位置'}, {from: 3, to: 3, title: '自环边的Tooltip'} ]); // 创建network实例 var container = document.getElementById('mynetwork'); var data = { nodes: nodes, edges: edges }; var options = { tooltip: { enabled: false } // 禁用默认tooltip,避免冲突 }; var network = new vis.Network(container, data, options); // 获取自定义tooltip元素 const customTooltip = document.getElementById('custom-tooltip'); const networkContainer = document.getElementById('mynetwork'); // 监听节点悬停事件 network.on('hoverNode', function(params) { const nodeId = params.node; const nodeData = nodes.get(nodeId); const nodePosition = network.getPositions(nodeId)[nodeId]; // 设置tooltip内容 customTooltip.textContent = nodeData.title; // 计算tooltip的位置(节点中心上方,避免遮挡节点) const tooltipWidth = customTooltip.offsetWidth; const tooltipHeight = customTooltip.offsetHeight; const left = networkContainer.offsetLeft + nodePosition.x - tooltipWidth / 2; const top = networkContainer.offsetTop + nodePosition.y - tooltipHeight - 10; // 定位并显示tooltip customTooltip.style.left = `${left}px`; customTooltip.style.top = `${top}px`; customTooltip.style.display = 'block'; }); // 监听边悬停事件 network.on('hoverEdge', function(params) { const edgeId = params.edge; const edgeData = edges.get(edgeId); const fromNodePos = network.getPositions(edgeData.from)[edgeData.from]; const toNodePos = network.getPositions(edgeData.to)[edgeData.to]; // 计算边的中心位置 const edgeCenterX = (fromNodePos.x + toNodePos.x) / 2; const edgeCenterY = (fromNodePos.y + toNodePos.y) / 2; // 设置tooltip内容 customTooltip.textContent = edgeData.title; // 计算tooltip位置(边中心上方) const tooltipWidth = customTooltip.offsetWidth; const tooltipHeight = customTooltip.offsetHeight; const left = networkContainer.offsetLeft + edgeCenterX - tooltipWidth / 2; const top = networkContainer.offsetTop + edgeCenterY - tooltipHeight - 10; // 定位并显示tooltip customTooltip.style.left = `${left}px`; customTooltip.style.top = `${top}px`; customTooltip.style.display = 'block'; }); // 监听鼠标移出节点/边事件,隐藏tooltip network.on('blurNode', function() { customTooltip.style.display = 'none'; }); network.on('blurEdge', function() { customTooltip.style.display = 'none'; }); // 点击空白处也隐藏tooltip network.on('click', function() { customTooltip.style.display = 'none'; }); </script> </body> </html>
关键细节解释
pointer-events: auto:这是让tooltip能被鼠标选中的核心设置,默认vis tooltip的pointer-events是none,所以根本没法选中文本。- 位置计算逻辑:通过
network.getPositions()获取节点的精确坐标,边的中心则取两端节点坐标的平均值,再微调tooltip位置避免遮挡目标元素。 - 事件闭环处理:用
hoverNode/hoverEdge触发显示,blurNode/blurEdge和点击空白处触发隐藏,确保tooltip的显示逻辑符合用户预期。
这样实现的tooltip会牢牢固定在节点或边的中心位置,你可以随意选中并复制里面的文本啦!
内容的提问来源于stack exchange,提问作者durila
相关产品推荐
相关产品推荐

