2014-01-24 86 views
6

基于两个D3示例:强制布局(http://bl.ocks.org/mbostock/1095795)和集群强制布局(http://bl.ocks.org/mbostock/1748247),我设法建立了具有几个独立重力的力布局,以控制节点位于顶部的节点之间的链接。D3js强制布局破坏并重置

// Set up map 
function map_init(){ 

    force = d3.layout.force() 
     .nodes(nodes) 
     .links(links) 
     .size([width, height]) 
     .on("tick", tick); 

    svg = d3.select("#map").append("svg") 
     .attr("width", width) 
     .attr("height", height); 

    link = $map.selectAll(".link"); 
    node = $map.selectAll(".node"); 

    d3.json("graph.json", function(error, graph) { 

     // set up nodes 
     for(i = 0; i < graph.nodes.length; i++){   
      nodes.push(graph.nodes[i]); 
     } 

     // position nodes to three different gravity centres based on theme 
     for(i = 0; i < nodes.length; i++){ 
      if (nodes[i].theme == "theme1"){ 
       nodes[i].cx = 100; 
       nodes[i].cy = 100; 
      } else if (nodes[i].theme == "theme2"){ 
       nodes[i].cx = 300; 
       nodes[i].cy = 300; 
      } else if (nodes[i].theme == "theme3"){ 
       nodes[i].cx = 500; 
       nodes[i].cy = 500; 
      } 
     } 

     // link nodes of the same theme 
     theme1_nodes = nodes.filter(function(d){ return (d.theme == "theme1"); }); 
     theme2_nodes = nodes.filter(function(d){ return (d.theme == "theme2"); }); 
     theme3_nodes = nodes.filter(function(d){ return (d.theme == "theme3"); }); 
     for (i = 0; i < theme1_nodes.length-1; i++){ 
      links.push({ source: theme1_nodes[i], target: theme1_nodes[i+1] }); 
     } 
     for (i = 0; i < theme2_nodes.length-1; i++){ 
      links.push({ source: theme2_nodes[i], target: theme2_nodes[i+1] }); 
     } 
     for (i = 0; i < theme3_nodes.length-1; i++){ 
      links.push({ source: theme3_nodes[i], target: theme3_nodes[i+1] }); 
     } 

     start(); 

    }); 

} 

// Start 
function start() { 

    link = link.data(force.links(), function(d) { return d.source.id + "-" + d.target.id; }); 
    link.enter() 
    .insert("svg:line") 
     .attr("class", "link"); 
    link.exit() 
     .remove(); 

    node = node.data(force.nodes(), function(d) { return d.id; }); 
    var nodeEnter = node.enter() 
      .append("svg:g") 
      .attr("class", "node"); 
     .on("click", map_nodeClick); 
    node.exit().remove(); 

    // Enter node information 
    nodeEnter.each(function(d) { 
     theTitle = d3.select(this).append("svg:text") 
     .attr("font-family", "Helvetica") 
      .attr("class", "title") 
     .text(d.title); 
    }); 

    // More content to go into each node 
    // . 
    // . 
    // . 

    force.start(); 

} 

// Tick 
function tick(e) { 

    node 
     .each(gravity(.2 * e.alpha)) 
     .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; }); 

} 

// Gravity 
function gravity(alpha) { 

    return function(d) { 
    d.y += (d.cy - d.y) * alpha; 
    d.x += (d.cx - d.x) * alpha; 
    }; 

} 

// Set up when page first loads 
map_init(); 

为了重置/随时重启力布局无需重新加载页面,我势必以下功能复位按钮:

// Remove force layout and data 
function map_remove(){ 

    node.remove(); 
    link.remove(); 
    svg.remove(); 
    nodes = []; 
    links = []; 

} 

// Reset button 
$('a#reset').click(function(e){ 

    e.preventDefault(); 

    map_remove(); 
    map_init(); 

}); 

该网页显示由组访问的设备上人。只在早上加载一次,然后在iPad Safari上运行12个小时。理想情况下,节点之间的链接根据用户输入(要实施)动态变化。除了强制布局外,网页上还有其他信息。需要重新启动/重置强制布局而不重新加载页面的选项。

  1. 是否有内置的方法来破坏D3强制布局及其数据?
  2. 目前这工作正常,因为没有额外的DOM元素被创建,并没有从检查员发现错误。但是我不确定如何检查所有D3对象是否已被清空/清空,因此没有重复数据被存储/累积?
  3. 由于某些原因,目前每次重置都会将节点拉近和靠近地图中心。我错过了map_remove()函数中的一些东西吗?
  4. 完全重新启动D3强制布局可以在任何时候提高浏览器的性能吗?即清理内存以绘制SVG?

回答

9
  1. 不需要手动操作。
  2. 你可以看看DOM,但看起来你正在删除所有东西。
  3. 我猜这是因为你实际上并没有从force布局中删除节点/链接。在某些情况下,您已将变量nodeslinks提供给力布局。改变这些名称指向的内容(即[])不会更改强制布局中的引用。也就是说,数据对象仍然存在并被引用。有两种方法可以将其删除。您可以修改nodeslinks(例如,使用.slice()),或者在强制布局中显式重置它们。

    nodes = []; links = []; force.nodes(nodes); force.links(links);

  4. 很难说没有一个具体的例子,但得到的答复是最有可能没有。 JavaScript是垃圾收集,所以手动做不应该有影响。

    nodeCircles = {}; 
    node.remove(); 
    link.remove(); 
    svg.clear(); 
    nodes = []; 
    links = []; 
    

    只是把这个变成一个方法,然后重新创建你的力量和SVG:

+0

对不起,我对于“...到位(例如.slice())...”有点困惑。 是应该'splice()'? – Carr

+0

您可以同时使用这两者,具体取决于您想要做什么。 –

2

我做到了。这很好。