You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 10:57:35