如何为3d-force-graph添加Tweakpane GUI节点属性点击展示功能
解决方案:点击节点在Tweakpane展示属性及相邻节点/链接信息
我来帮你搞定这个节点属性展示的问题!结合你现有的3d-force-graph和Tweakpane代码,我们可以通过动态更新Tweakpane面板的方式,在点击节点时展示完整的节点属性、相邻节点和连接链接信息,同时保留你已有的缩放居中功能。
步骤1:初始化Tweakpane结构
首先调整你的Tweakpane初始化代码,预留一个专门用于展示节点信息的文件夹,初始状态可以放提示文本:
const pane = new Pane(); // 保留你的设置文件夹 const settingsFolder = pane.addFolder({ title: 'Settings', expanded: false }); settingsFolder.addBinding(PARAMS, 'name'); settingsFolder.addBinding(PARAMS, 'label'); settingsFolder.addBinding(PARAMS, 'id'); // 新增节点信息展示文件夹 let nodeInfoFolder = pane.addFolder({ title: 'Node Information', expanded: true }); // 初始提示 nodeInfoFolder.addButton({ title: 'Click any node to view details' });
步骤2:编写动态更新节点信息的函数
这个函数会在点击节点时被调用,负责清空旧的信息、生成新的面板控件,包括基础属性、自定义attributes、相邻节点和连接链接:
function updateNodeInfo(selectedNode) { // 清空旧的节点信息控件 nodeInfoFolder.dispose(); // 创建新的文件夹,以节点label命名 nodeInfoFolder = pane.addFolder({ title: `Node: ${selectedNode.label}`, expanded: true }); // 1. 添加节点基础属性 nodeInfoFolder.addInput(selectedNode, 'label', { label: 'Label' }); nodeInfoFolder.addInput(selectedNode, 'id', { label: 'ID' }); nodeInfoFolder.addInput(selectedNode, 'description', { label: 'Description' }); nodeInfoFolder.addInput(selectedNode, 'size', { label: 'Size', disabled: true }); // 设为disabled防止误修改 nodeInfoFolder.addInput(selectedNode, 'color', { label: 'Color' }); // 2. 添加节点的attributes子属性 const attrsFolder = nodeInfoFolder.addFolder({ title: 'Advanced Attributes', expanded: false }); Object.entries(selectedNode.attributes).forEach(([key, value]) => { attrsFolder.addInput({ [key]: value }, key, { disabled: true }); }); // 3. 获取并展示相邻节点和连接链接 const graphData = graph.getGraphData(); // 这里的graph是你的3d-force-graph实例 // 筛选当前节点相关的链接 const connectedLinks = graphData.links.filter( link => link.source.id === selectedNode.id || link.target.id === selectedNode.id ); // 收集相邻节点(去重) const neighboringNodes = new Set(); connectedLinks.forEach(link => { const neighbor = link.source.id === selectedNode.id ? link.target : link.source; neighboringNodes.add(neighbor); }); // 展示相邻节点 const neighborsFolder = nodeInfoFolder.addFolder({ title: `Neighbors (${neighboringNodes.size})`, expanded: false }); neighboringNodes.forEach(node => { // 生成可点击的按钮,点击后自动切换到该节点 neighborsFolder.addButton({ title: node.label || node.id }).on('click', () => { graph.emit('node-click', node); }); }); // 展示连接的链接 const linksFolder = nodeInfoFolder.addFolder({ title: `Connected Links (${connectedLinks.length})`, expanded: false }); connectedLinks.forEach((link, idx) => { const linkName = `${link.source.id} → ${link.target.id}`; linksFolder.addInput({ [`Link ${idx+1}`]: linkName }, `Link ${idx+1}`, { disabled: true }); // 如果链接有自定义属性,也可以在这里扩展展示 if (link.attributes) { const linkAttrsFolder = linksFolder.addFolder({ title: `Link ${idx+1} Attributes`, expanded: false }); Object.entries(link.attributes).forEach(([key, value]) => { linkAttrsFolder.addInput({ [key]: value }, key, { disabled: true }); }); } }); }
步骤3:整合节点点击事件
修改你现有的onNodeClick回调,把缩放居中逻辑和节点信息更新逻辑结合起来:
graph.onNodeClick(node => { // 保留你的缩放居中逻辑 const distance = 40; const distRatio = 1 + distance/Math.hypot(node.x, node.y, node.z); const newPos = node.x || node.y || node.z ? { x: node.x * distRatio, y: node.y * distRatio, z: node.z * distRatio } : { x: 0, y: 0, z: distance }; // 处理原点节点的特殊情况 // 相机动画跳转 graph.cameraPosition(newPos, node, 3000); // 调用更新节点信息的函数 updateNodeInfo(node); });
关键注意点
- 确保
graph变量是你的3d-force-graph实例(比如你初始化时的const graph = ForceGraph3D(...)) - 如果不需要让用户编辑属性,把
addInput的disabled参数设为true,避免误操作 - 链接的属性展示是可选的,如果你的JSON里没有链接属性,可以删除这部分代码
- 相邻节点按钮支持点击跳转,进一步提升交互体验
内容的提问来源于stack exchange,提问作者greg.gan
相关产品推荐
相关产品推荐

