我已经使用d3创建了一个强制布局,它的工作原理很好.我的初始数据是从一个json文件加载的,图表中绘制的技术类似于
this d3.js example:
现在图表在屏幕上,我需要从通过网络接口接收到的数据中添加,更新和删除节点.我有添加和删除方法工作,但我找不到更新现有节点属性的正确方法.
从我读过的阅读我收集正确的技术是更改数据源,然后使用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属性时,我得到的节点作为基准是节点数组中的最后一个节点.即包含分层节点数据而不是单个节点对象.
任何指针都将不胜感激,我花了太多时间在这个:)
解决方法
您需要多个点.我从你的问题得到的是:’如何使用可重用的模式’
对这个问题的简单回答,是告诉你阅读Mike Bostock:towards reusable charts的这个优秀的教程
如果你想要更多的信息,这个选择的文件可以是有趣的:
> selections documentation
> how selections work
> A bar chart,part 2:可能最有趣的是了解更新是如何工作的.
现在,这是一个草案,我将为您的特定问题做的实现:
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