2012-09-18 40 views
11

我已经使用d3创建了一个强制布局,并且效果很好。我最初的数据是从JSON文件加载和图表绘制类似于this d3.js example技术:在d3 Force Layout中更新现有节点

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); 
     } 
    }) 
} 

我是否采取正确的方法呢?当我尝试这段代码时,我试图在圆上设置radius属性时获得的节点是节点数组中的最后一个节点。即包含分层节点数据而不是单个节点对象的数据库。

任何指针将不胜感激,我已经花了太多时间在这:)

+0

我有同样的问题,虽然在一个更简单的环境。你找到解决方案吗? – 2013-03-01 14:27:53

+0

可以把你的代码放到在线编辑器中,例如http://phrogz.net/JS/d3-playground/#BlankDefault – ppoliani

回答

7

有迹象表明,你需要多点。我从你的问题,得到的是:“我如何使用可重复使用的模式”

简单的回答这个问题,会告诉你读迈克·博斯托克的精彩教程: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