我是D3的新手,正在研究json数据是动态的强制图。我能够在接收到新数据后更改力图,但这会产生弹跳效果。创建我的力图的代码是:
<div class="graph"></div> <script> var w = 660, h = 700, r = 10; var vis = d3.select(".graph") .append("svg:svg") .attr("width", w) .attr("height", h) .attr("pointer-events", "all") .append('svg:g') .call(d3.behavior.zoom().on("zoom", redraw)) .append('svg:g'); vis.append('svg:rect') .attr('width', w) .attr('height', h) .attr('fill', 'rgba(1,1,1,0)'); function redraw() { console.log("here", d3.event.translate, d3.event.scale); vis.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); }; var force = d3.layout.force() .gravity(.05) .charge(-200) .linkDistance( 260 ) .size([w, h]); var svg = d3.select(".text") .append("svg") .attr("width", w) .attr("height", h); d3.json(graph, function(json) { var nodeList = json.nodes; var link = vis.selectAll("line") .data(json.links) .enter() .append("line") .attr("stroke-opacity", function(d) { if(d.label == 'is a') { return '0.8'; } else { return '0.2'; }; }) .attr("stroke-width", function(d) { if(d.value !== null) { return d.value; } else { return 2; }; }) .style("stroke", function(d) { if(d.color !== null) { return d.color; }; }) .on("mouseover", function() { d3.select(this) .style("stroke", "#999999") .attr("stroke-opacity", "1.0"); }) .on("mouseout", function() { d3.select(this) .style("stroke", function(d) { if(d.color !== null) { return d.color; }; }) .attr("stroke-opacity", function(d) { if(d.label == 'is a') { return '0.8'; } else { return '0.2'; }; }) }); link.append("title") .text(function(d) { return d.label } ); var node = vis.selectAll("g.node") .data(json.nodes) .enter() .append("svg:g") .attr("class","node") .call(force.drag); node.append("svg:circle") .attr("r", function(d) { if (d.size > 0) { return 10+(d.size*2); } else { return 10; } }) .attr("id", function(d) { return "Node;"+d.id; } ) .style("fill", function(d) { if(d.style == 'filled') { return d.color; }; }) .style("stroke", function(d) { if(d.style !== 'filled') { return d.color; }; }) .style("stroke-width", "2") .on("mouseover", function() { d3.select(this).style("fill", "#999"); fade(.1); }) .on("mouseout", function(d) { if (d.style == 'filled') { d3.select(this).style("fill",d.color);fade(1); } else { d3.select(this).style("stroke",d.color); d3.select(this).style("fill","black"); } fade(1); }); node.append("title") .text(function(d) { return d.Location; } ); force.nodes(json.nodes) .links(json.links) .on("tick", tick) .alpha(1) .start(); function tick() { node.attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }) .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); } }); </script>
我可以通过再次调用整个函数来在接收到新的json字符串时创建新图。这将创建一个新图代替旧图。接收到值后,我无法使用新的值集更新旧图;我图中的节点没有改变,只是它们之间的关系改变了。
我确实偶然发现了一个示例(http://bl.ocks.org/1095795),其中删除并重新创建了一个新节点,但是实现有些不同。
任何指针或帮助将不胜感激。
好吧,我可以找到浏览解决方案的方法,并将其发布在此处,以供需要此主题的任何人使用。这个想法是创建图的对象,并处理节点和链接数组。JS代码如下:
var graph; function myGraph(el) { // Add and remove elements on the graph object this.addNode = function (id) { nodes.push({"id":id}); update(); }; this.removeNode = function (id) { var i = 0; var n = findNode(id); while (i < links.length) { if ((links[i]['source'] == n)||(links[i]['target'] == n)) { links.splice(i,1); } else i++; } nodes.splice(findNodeIndex(id),1); update(); }; this.removeLink = function (source,target){ for(var i=0;i<links.length;i++) { if(links[i].source.id == source && links[i].target.id == target) { links.splice(i,1); break; } } update(); }; this.removeallLinks = function(){ links.splice(0,links.length); update(); }; this.removeAllNodes = function(){ nodes.splice(0,links.length); update(); }; this.addLink = function (source, target, value) { links.push({"source":findNode(source),"target":findNode(target),"value":value}); update(); }; var findNode = function(id) { for (var i in nodes) { if (nodes[i]["id"] === id) return nodes[i];}; }; var findNodeIndex = function(id) { for (var i=0;i<nodes.length;i++) { if (nodes[i].id==id){ return i; } }; }; // set up the D3 visualisation in the specified element var w = 500, h = 500; var vis = d3.select("#svgdiv") .append("svg:svg") .attr("width", w) .attr("height", h) .attr("id","svg") .attr("pointer-events", "all") .attr("viewBox","0 0 "+w+" "+h) .attr("perserveAspectRatio","xMinYMid") .append('svg:g'); var force = d3.layout.force(); var nodes = force.nodes(), links = force.links(); var update = function () { var link = vis.selectAll("line") .data(links, function(d) { return d.source.id + "-" + d.target.id; }); link.enter().append("line") .attr("id",function(d){return d.source.id + "-" + d.target.id;}) .attr("class","link"); link.append("title") .text(function(d){ return d.value; }); link.exit().remove(); var node = vis.selectAll("g.node") .data(nodes, function(d) { return d.id;}); var nodeEnter = node.enter().append("g") .attr("class", "node") .call(force.drag); nodeEnter.append("svg:circle") .attr("r", 16) .attr("id",function(d) { return "Node;"+d.id;}) .attr("class","nodeStrokeClass"); nodeEnter.append("svg:text") .attr("class","textClass") .text( function(d){return d.id;}) ; node.exit().remove(); force.on("tick", function() { node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); }); // Restart the force layout. force .gravity(.05) .distance(50) .linkDistance( 50 ) .size([w, h]) .start(); }; // Make it all go update(); } function drawGraph() { graph = new myGraph("#svgdiv"); graph.addNode('A'); graph.addNode('B'); graph.addNode('C'); graph.addLink('A','B','10'); graph.addLink('A','C','8'); graph.addLink('B','C','15'); }