2012-09-18 28 views
11

He creado un diseño de fuerza con d3 y funciona bien. Mi inicial de datos se carga desde un archivo JSON y la carta se dibuja con técnicas que son similares a this d3.js example:Actualizar nodos existentes en un diseño de fuerza d3

enter image description here

Ahora que la tabla se encuentra en la pantalla tengo que añadir, actualizar y eliminar nodos en el volar desde los datos que recibo sobre un socket web. He agregado y eliminado métodos que funcionan, pero no puedo encontrar la forma correcta de actualizar las propiedades de un nodo existente.

De acuerdo con la lectura que he realizado, recojo que la técnica correcta es cambiar la fuente de datos, luego actualice la tabla usando el método enter().

Para actualizar un nodo que estoy haciendo lo siguiente:

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

La función de actualización actualiza entonces los nodos con:

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

estoy tomando el enfoque correcto para esto? Cuando pruebo este código, el nodo que obtengo como dato al intentar establecer el atributo de radio en el círculo es el último nodo en la matriz de nodos. Es decir. el que contiene los datos del nodo jerárquico en lugar de un objeto de nodo único.

Cualquier punteros sería muy apreciada, he pasado demasiado tiempo en esto :)

+0

tengo el mismo problema, aunque en un contexto mucho más simple. ¿Encontraste una solución? –

+0

podría poner su código en un editor en línea, por ejemplo http://phrogz.net/JS/d3-playground/#BlankDefault – ppoliani

Respuesta

7

Hay varios puntos que usted necesita. Lo que recibo de sus preguntas es: '¿cómo se utiliza el patrón reutilizable'

La respuesta simple a esta pregunta, sería para decirle a leer este excelente tutorial de Mike Bostock: towards reusable charts

Si desea tener más información, esta selección de documentos puede ser interesante:

Ahora, aquí es un proyecto de las implementaciones que haría para su tema en particular:

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` 

Como podrán ver, el objetivo no es tener una función para añadir un nuevo nodo. El objetivo es volver a dibujar todo el gráfico dirigido por la fuerza actualizando o eliminando nodos existentes y agregando los nuevos nodos. De esta forma, el código de dibujo se escribe solo una vez, luego solo cambian los datos.

Para leer más, esta pregunta fue mi mina de oro cuando por primera vez abordado este tema: Updating links on a force directed graph from dynamic json data

Cuestiones relacionadas