javascript - 更新 d3 Force Layout 中的现有节点

标签 javascript d3.js transition force-layout

我使用 d3 创建了一个强制布局,它运行良好。我的初始数据是从一个 json 文件加载的,图表是用类似于 this d3.js example 的技术绘制的。 :

enter image description here

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

根据我所进行的阅读,我认为正确的技术是更改数据源,然后使用 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);
      }
   })
}

我对此采取了正确的方法吗?当我尝试使用此代码时,尝试在圆上设置半径属性时作为基准获得的节点是节点数组中的最后一个节点。 IE。包含分层节点数据而不是单个节点对象的对象。

任何指点将不胜感激,我在这上面花了太多时间:)

最佳答案

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

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

如果您想了解更多信息,这些文档选择可能会很有趣:

现在,这是我针对您的特定问题所做的实现草案:

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`

正如您可能看到的那样,目标不是具有添加新节点的功能。目标是通过仅更新或删除现有节点并添加新节点来重绘整个力导向图。这样绘图代码只写一次,然后只有数据发生变化。

为了进一步阅读,这个问题是我第一次解决这个问题时的金矿:Updating links on a force directed graph from dynamic json data

关于javascript - 更新 d3 Force Layout 中的现有节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12479809/

相关文章:

javascript - 我怎么知道 iframe/popup 内容已加载/准备好?

javascript - 如果所有三个单选按钮均为 false,则不验证

javascript - 在 dc.js 中更改图例值

html - 无法使用 css 获得流畅的下拉菜单

javascript - 如何在动态创建的对象上启用 CSS 过渡

javascript - 将值设置为来自angularjs Controller 的html标签不起作用

javascript - 如何使用 svg "focusable"制作 iframe

javascript - D3 图表未显示

javascript - 如何在 D3 中循环 JavaScript 对象?

C#平滑对象移动