json d3.js force-layout

Actualización de enlaces en un gráfico dirigido por fuerza a partir de datos json dinámicos



d3.js force-layout (3)

Además de llamar a drawGraph() en la función lista, también puede insertar el código publicado dentro de un bloque <script></script> .

Así es como la mayoría de los tutoriales en el sitio d3 lo manejan.

Soy nuevo en D3 y trabajo en un gráfico de fuerza dirigida donde los datos json son dinámicos. Puedo cambiar el gráfico de fuerza al recibir nuevos datos, pero eso ocurre con un efecto de salto. El código que crea mi gráfico de fuerza es:

<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>

Puedo crear un nuevo gráfico cuando se recibe una nueva cadena json al recuperar toda la función nuevamente. Esto crea un nuevo gráfico en lugar del anterior. No puedo actualizar el gráfico anterior con el nuevo conjunto de valores a medida que se reciben los valores; los nodos en mi gráfica no cambian, solo la relación entre ellos cambia.

Encontré un ejemplo ( http://bl.ocks.org/1095795 ) donde se elimina y se recrea un nuevo nodo, pero la implementación es un poco diferente.

Cualquier sugerencia o ayuda será realmente apreciada.


Bien, podría encontrar la solución navegando, publicarla aquí para cualquier persona que necesite ayuda con este tema. La idea es crear un objeto del gráfico y jugar con los conjuntos de nodos y enlaces. El código JS es como sigue:

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


Tomé Rahuls buen ejemplo, hice algunos cambios y publiqué un bl.ock completo con animación a lo largo del tiempo si alguien está interesado en un ejemplo completamente funcional. Agregar / eliminar enlaces / nodos realmente debería ser más fácil que esto, pero aún así genial.

http://bl.ocks.org/ericcoopey/6c602d7cb14b25c179a4