2015-06-30 4 views
0

У меня есть график компоновки сил, который работает так, как ожидалось. Он читает график с JSON на диске и отображает его. Теперь у меня есть сервер, нажимающий данные на клиентскую страницу с помощью socket io. Эти данные представляют собой JSON, содержащий данные узла и ссылки.Как динамически обновлять график расположения сил d3.js?

Как обновить макет и обновить макет, когда он получит этот новый JSON с сервера?

var width = 1900, 
height = 1100; 

var color = d3.scale.category20(); 

var force = d3.layout.force() 
    .charge(-120)   
    .linkDistance(30) 
    .size([width, height]); 

var svg = d3.select("body").append("svg") 
    .attr("width", width) 
    .attr("height", height); 


var networkData = {}; 
var socket = io.connect('http://localhost:3000'); 

socket.on("networkData", function (data) { 
    networkData = data; //This is the data I want to use 
}); 


d3.json("data.json", function(error, graph) { //"data.json" is the data 
    if (error) throw error;     // currently being used 
               // want to use "networkData" 
force 
    .nodes(graph.nodes) 
    .links(graph.links) 
    .start(); 

var link = svg.selectAll(".link") 
    .data(graph.links)   
    .enter().append("line") 
    .attr("class", "link") 
    .style("stroke-width", function(d) { return Math.sqrt(d.value); }); 

var node = svg.selectAll(".node") 
    .data(graph.nodes) 
    .enter().append("circle") 
    .attr("class", "node") 
    .attr("r", 5) 
    .style("fill", "orange") 
    .call(force.drag); 

node.append("title") 
    .text(function(d) { return d.name; }); 

force.on("tick", function() { 
    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; }); 

    node.attr("cx", function(d) { return d.x; }) 
    .attr("cy", function(d) { return d.y; }); 
}); 
}); 

EDIT

Я обновил код, как Гильермо Гарсия предложил следующее:

socket.on("networkData", function (data) { 
    force.stop() 
    render(data); 
    force 
     .nodes(data.nodes) 
     .links(data.links) 
     .start();    
}); 

function render(data) { 

    var link = svg.selectAll(".link") 
     .data(data.links)  
     .enter().append("line") 
     .attr("class", "link") 
     .style("stroke-width", function(d) { return Math.sqrt(d.value); }); 

    var node = svg.selectAll(".node") 
     .data(data.nodes) 
     .enter().append("circle") 
     .attr("class", "node") 
     .attr("r", 5) 
     .style("fill", "orange") 
     .call(force.drag); 

    node.append("title") 
     .text(function(d) { return d.name; }); 

force.on("tick", function() { 
    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; }); 

    node.attr("cx", function(d) { return d.x; }) 
    .attr("cy", function(d) { return d.y; }); 
}); 
} 

Однако график работы только для первого networkData JSON, отправленная с сервера. Я также должен вручную обновить страницу, чтобы эти данные отображались.

Почему данные не работают для> 2-х файлов данных? Как можно динамически обновлять страницу? (т. е. не нужно вручную обновлять)

ответ

1

Вы пробовали создать функцию визуализации и вызвать ее в событии socket.io?

Рендер функция должна иметь весь код с var link = svg.selectAll(".link") в force.on("tick", function() {

var link = svg.selectAll(".link") 
.data(graph.links)  

... 
... 

force.on("tick", function() { 
    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; }); 

    node.attr("cx", function(d) { return d.x; }) 
    .attr("cy", function(d) { return d.y; }); 
}); 

Удачи!

+0

Я обновил OP с вашими предложениями, но столкнулся с большим количеством проблем. – Shengus

+0

Было бы слишком сложно создать jsfiddle с ошибкой? Кроме того, взгляните на этот ответ, я думаю, что это аналогичный случай http://stackoverflow.com/a/18378803/1923565 –

+0

Я не думаю, что можно эмулировать нажатие данных с сервера с помощью jsfiddle. Я рассмотрю другую тему для идей. – Shengus

0

Возможно, это может быть немного сложнее реализовать для вашего случая, но я уверен, что мой код может дать вам хотя бы некоторые идеи. Таким образом, это функции, которые я в основном использую для очистки презентации и добавить новые узлов из базы данных динамически. Вы можете увидеть результат here. Эти строки также проверяют наличие дубликатов и их фильтрацию. Если вам нужно другое определение или переменные, дайте мне знать.

 cleanPresentation: function() { 
      svg.remove(); 
      nodeCircles = {}; 
      alreadyThere = false; 
     }, 
     getAlreadyThere: function() { 
      return alreadyThere; 
     }, 
     createGraph: function (newJSON) { 
      if (alreadyThere) { 
       svg.remove(); 
       nodeCircles = {}; 
      } 
      this.updateForceUsingNewNodes(this.generateObjects(newJSON)); 
      currentJSON = newJSON; 
      if (alreadyThere == false) { 
       this.setbasiczoom(); 
      } 
      alreadyThere = true; 
     }, 
     updateGraph: function (newJSON) { 
      svg.remove(); 
      this.findDuplicatesAndSetEmpty(newJSON); 
      this.deleteEmptyObjectsInJSON(newJSON); 
      currentJSON = currentJSON.concat(newJSON); 
      this.updateForceUsingNewNodes(this.generateObjects(currentJSON)); 
     }, 
     findDuplicatesAndSetEmpty: function (newJSON) { 
      for (var i = 0; i < currentJSON.length; i++) { 
       for (var o = 0; o < newJSON.length; o++) { 
        if ((currentJSON[i].source.ID == newJSON[o].source) && (currentJSON[i].target.ID == newJSON[o].target) 
         || (currentJSON[i].source.ID == newJSON[o].target) && (currentJSON[i].target.ID == newJSON[o].source)) { 
         newJSON[o] = {}; 
        } 
       } 
      } 
     }, 
     deleteEmptyObjectsInJSON: function (json) { 
      for (var i = 0; i < json.length; i++) { 
       var y = json[i].source; 
       if (y === "null" || y === null || y === "" || typeof y === "undefined") { 
        json.splice(i, 1); 
        i--; 
       } 
      } 
     }, 
     updateGraphByRemoveElement: function (clickedNode, index) { 
      svg.remove(); 
      var json4Splicing = currentJSON; 
      for (var i = 0; i < json4Splicing.length; i++) { 
       if (json4Splicing[i].source.ID == clickedNode.ID) { 
        json4Splicing[i] = {}; 
       } else if (json4Splicing[i].target.ID == clickedNode.ID) { 
        json4Splicing[i] = {}; 
       } 
      } 
      familytree.deleteEmptyObjectsInJSON(json4Splicing); 
      familytree.deleteNode(force.nodes(), clickedNode); 
      currentJSON = json4Splicing; 
      familytree.updateForceRemoveElement(familytree.generateObjects(currentJSON)); 
     }, 
     deleteNode: function (allNodes, clickedNode) { 
      allNodes.forEach(function (node) { 
       if (node == clickedNode) { 
        force.links().forEach(function (link) { 
         if (node.ID == link.source.ID) { 
          link.target.linkCount--; 
         } 
         if (node.ID == link.target.ID) { 
          link.source.linkCount--; 
         } 
        }); 
        node.linkCount = 0; 
       } 
      }); 
     }, 
     generateObjects: function (json) { 
      json.forEach(function (link) { 
       if (typeof(link.source) == "string") { 
        link.source = nodeCircles[link.source] || (nodeCircles[link.source] = {name: link.sourceName, significance: link.sourceSign, uniquename: link.sourceUName, ID: link.source, class: link.sourceClass, relation: link.relation, race: link.sourceRace, linkCount: 0}); 
        link.source.linkCount++; 
       } 
       if (typeof(link.target) == "string") { 
        link.target = nodeCircles[link.target] || (nodeCircles[link.target] = {name: link.targetName, significance: link.targetSign, uniquename: link.targetUName, ID: link.target, class: link.targetClass, relation: link.relation, race: link.targetRace, linkCount: 0}); 
        link.target.linkCount++; 
       } 
      }); 
      return json; 
     }, 
     updateForceRemoveElement: function (links) { 
      force.nodes(d3.values(nodeCircles).filter(function (d) { 
       return d.linkCount; 
      })); 
      force.links(d3.values(links)); 
      familytree.initializeGraph(); 
     }, 
     updateForceUsingNewNodes: function (links) { 
      force.nodes(d3.values(nodeCircles).filter(function (d) { 
       return d.linkCount; 
      })); 
      force.links(d3.values(links)); 
      this.initializeGraph(); 
     } 

 Смежные вопросы

  • Нет связанных вопросов^_^