Javascript 更新d3 Force布局中的现有节点

Javascript 更新d3 Force布局中的现有节点,javascript,d3.js,transition,force-layout,Javascript,D3.js,Transition,Force Layout,我使用d3创建了一个force布局,效果很好。我的初始数据是从json文件加载的,图表的绘制技术类似于: 现在图表已经显示在屏幕上,我需要在通过web套接字接收的数据中动态添加、更新和删除节点。我有添加和删除方法,但是我找不到更新现有节点属性的正确方法 从我所进行的阅读中,我收集到正确的方法是更改数据源,然后使用enter()方法更新图表 要更新节点,我将执行以下操作: function updateNode(id, word, size, trend, parent_id){ v

我使用d3创建了一个force布局,效果很好。我的初始数据是从json文件加载的,图表的绘制技术类似于:

现在图表已经显示在屏幕上,我需要在通过web套接字接收的数据中动态添加、更新和删除节点。我有添加和删除方法,但是我找不到更新现有节点属性的正确方法

从我所进行的阅读中,我收集到正确的方法是更改数据源,然后使用enter()方法更新图表

要更新节点,我将执行以下操作:

function updateNode(id, word, size, trend, parent_id){    
  var updateNode = nodes.filter(function(d, i) { return d.id == id ? this : null; });
  if(updateNode[0]){   
    updateNode.size = Number(size);
    updateNode.trend = trend;
    nodes[updateNode.index] = updateNode;      
    update();
  }
}
然后,更新功能使用以下内容更新节点:

function update(){
  node = vis.selectAll('.node')
  .data(nodes, function(d) {
    return d.id;
  })

  createNewNodes(node.enter());
  node.exit().remove();
  force.start();
}

function createNewNodes(selection){    
  var slct = selection.append('g')
  .attr('class', 'node')
  .call(force.drag);

  slct.append('circle')
    .transition()
    .duration(500)
    .attr('r', function(d) {
      if(d.size){
        return Math.sqrt(sizeScale(d.size)*40);
      }
   })
}
我是否采取了正确的方法?当我尝试此代码时,当我尝试在圆上设置半径属性时,作为基准的节点是节点数组中的最后一个节点。即,包含分层节点数据而不是单个节点对象的节点


任何建议都将不胜感激,我在这方面花了太多时间:)

您需要多个要点。我从你们的问题中得到的是:“我如何使用可重用模式?”

这个问题的简单答案是告诉您阅读Mike Bostock的这篇优秀教程:

如果您想了解更多信息,可以选择以下文档:

  • :了解更新如何工作可能是最有趣的
现在,这里是我将为您的特定问题所做的实现草案:

function ForceGraph(selector,data) {
   // This is the class that will create a graph

   var _data = data  
   // Local variable representing the forceGraph data 

   svg = d3.select(selector)
      .append('svg')
   // Create the initial svg element and the utilities you will need. 
   // These are the actions that won't be necessary on update. 
   // For example creating the axis objects, your variables, or the svg container

   this.data = function(value) {
      if(!arguments.length) {
         // accessor
         return _data;
      }
      _data = value;
      return this;
      // setter, returns the forceGraph object
   }

   this.draw = function() {
      // draw the force graph using data

      // the method here is to use selections in order to do: 
      // selection.enter().attr(...) // insert new data
      // selection.exit().attr(...) // remove data that is not used anymore
      // selection.attr(...) // 

   }
}

var selector = "#graphId";
var data = {nodes: [...],links: [...]};
myGraph = new ForceGraph(selector,data);
// Create the graph object
// Having myGraph in the global scope makes it easier to call it from a json function or anywhere in the code (even other js files). 
myGraph.draw();
// Draw the graph for the first time 

// wait for something or for x seconds  

var newData = {nodes: [...],links: [...]};
// Get a new data object via json, user input or whatever
myGraph.data(newData);
// Set the graph data to be `newData`
myGraph.draw();
// redraw the graph with `newData`
正如您可能看到的,我们的目标不是要有一个函数来添加一个新节点。目标是通过仅更新或删除现有节点并添加新节点来重新绘制整个力定向图。这样,图形代码只编写一次,然后只更改数据


为了进一步阅读,当我第一次处理这个问题时,这个问题是我的金矿:

我也有同样的问题,尽管在一个更简单的背景下。您找到解决方案了吗?例如,您可以将代码放到在线编辑器中