2014-01-24 100 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

我做到了。這很好。