2013-05-01 37 views
6

Tôi đã thấy các giải pháp để tạo bố cục nhiều lực trên một trang, trong đó mỗi bố cục được chứa trong SVG của chính nó; tuy nhiên, tôi không thể tìm thấy trợ giúp về cách bao gồm nhiều bố trí lực trong một SVG đơn lẻ. Mỗi bố cục có dữ liệu riêng của nó được liên kết với nó.D3: Nhiều bố trí lực trong một SVG?

Ví dụ về những gì tôi hiện đang làm có thể được tìm thấy tại http://jsfiddle.net/connorgr/SRAJa/. Tôi đã bao gồm phần chính của mã bên dưới. Kết quả cuối cùng trông rất khủng khiếp như bố cục lực lượng không bao giờ được kích hoạt (hoặc xóa) cho tất cả trừ dữ liệu nút/liên kết cuối cùng. Có cách nào để ngăn chặn điều này xảy ra không?

Tôi không thể hợp nhất dữ liệu với nhau và chỉ sử dụng một bố cục vì trường hợp sử dụng cho hình ảnh tôi đang tạo.

/** 
    * Creates a force layout in svgObj for each element in graphs 
    * (svg) svgObj - The SVG to include the force layouts in 
    * (json) graphs - An array of {"nodes":[...],"links":[...]} objects 
    */ 
function generateMultiForce(svgObj, graphs) { 
    for(var i=0; i < graphs.length; i++) { 
    var graph = graphs[i]; 

    var graphArea = svgObj.append("g"); 

    var force = d3.layout.force() 
     .charge(-200) 
     .linkDistance(45) 
     .size([width, height]) 
     .nodes(graph.nodes) 
     .links(graph.links) 
     .start(); 

    var link = graphArea.selectAll(".link") 
     .data(graph.links) 
     .enter().append("line") 
      .attr("class", "link"); 

    var nodeGroup = graphArea.selectAll("g") 
     .data(graph.nodes) 
     .enter().append("g") 
     .call(force.drag); 

    var node = nodeGroup.append("circle") 
     .attr("class", "node") 
     .attr("r", 5) 
     .style("fill", function(d) { 
      return color(d.group); }); 

    var text = nodeGroup.append("text") 
     .attr("x", 8) 
     .attr("y", ".31em") 
     .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; }); 

     nodeGroup.attr("transform", function(d) { 
      return "translate("+d.x+","+d.y+")"; 
     }); 
    }); 
    } 
} 
+0

Dường như với tôi, sự kiện 'tick' là (theo nghĩa) toàn cầu. Tức là, bạn chỉ có thể có một trình xử lý cho một sự kiện 'tick', vì vậy cái cuối cùng bạn cài đặt sẽ được gọi. –

+0

Tìm hiểu kỹ hơn về mã nguồn D3 và dường như điều gì đang xảy ra. Rất tiếc. –

Trả lời

2

Bạn có thể viết hàm generateMultiForce như một plugin jquery - điều này dường như để giữ cho các đồ thị độc lập và áp dụng cách bố trí lực lượng để cả hai:

var width = 600, 
    height = 600; 

var color = d3.scale.category20(); 

var data = [ 
    { 
    "nodes": [ 
     {"name": "Hello"}, 
     {"name": "World"} 
    ], 
    "links": [ 
     {"source": 0, "target": 1, "value": 0.5} 
    ] 
    }, 
    { 
    "nodes": [ 
     {"name": "Zero"}, 
     {"name": "One"}, 
     {"name": "Two"} 
    ], 
    "links": [ 
     {"source": 0, "target": 1, "value": 0.25}, 
     {"source": 1, "target": 2, "value": 0.5}, 
     {"source": 2, "target": 0, "value": 0.25} 
    ] 
    } 
]; 

(function($) { 
    $.fn.generateMultiForce = function(svgObj) { 

     return this.each(function() { 
      var graph = this; 
      var graphArea = svgObj.append("g"); 

      var force = d3.layout.force() 
       .charge(-200) 
       .linkDistance(45) 
       .size([width, height]) 
       .nodes(graph.nodes) 
       .links(graph.links) 
       .start(); 

      var link = graphArea.selectAll(".link") 
       .data(graph.links) 
       .enter().append("line") 
       .attr("class", "link"); 

      var nodeGroup = graphArea.selectAll("g") 
       .data(graph.nodes) 
       .enter().append("g") 
       .call(force.drag); 

      var node = nodeGroup.append("circle") 
       .attr("class", "node") 
       .attr("r", 5) 
       .style("fill", function(d) { 
        return color(d.group); }); 

      var text = nodeGroup.append("text") 
       .attr("x", 8) 
       .attr("y", ".31em") 
       .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; }); 

       nodeGroup.attr("transform", function(d) { 
        return "translate("+d.x+","+d.y+")"; 
       }); 
      }); 
     }); 
    }; 
})(jQuery); 

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

$(data).generateMultiForce(svgTest); 
6

Phương pháp sau đây hạn chế lực lượng, nút, và liên kết dữ liệu với bố cục theo hướng lực lượng tương ứng của chúng. Bằng cách này, bạn có thể thêm nhiều bố trí như bạn muốn cùng một SVG mà không gây nhiễu liên nút. Mỗi bố cục có thể được định dạng riêng lẻ. Nếu cuối cùng bạn muốn các bố cục ảnh hưởng lẫn nhau, bạn có thể chỉnh sửa các chức năng đánh dấu tương ứng của chúng.

function layout1(inputNodes, inputLinks) { 
    var force = d3.layout.force(); 
    var nodes = force.nodes(); 
    var links = force.links(); 

    var update = function() { 
     //append nodes and links from data 

     force.on("tick",function(e){ 
     //tick movement 

     } 
    } 
    for(var i=0; i<inputNodes.length; i++){ 
     nodes.push(inputNodes[i]); 
    } 
    for(var i=0; i<inputLinks.length; i++){ 
     links.push(inputLinks[i]); 
    } 
    update(); 
} 

Bây giờ bố trí lực lượng hướng thứ hai có thể có cấu trúc giống hệt nhau, và những cái tên biến tương tự cũng như:

function layout2(inputNodes, inputLinks) { 
    var force = d3.layout.force(); 
    var nodes = force.nodes(); 
    var links = force.links(); 

    var update = function() { 
     //append nodes and links from data 

     force.on("tick",function(e){ 
     //tick movement 

     } 
    } 
    for(var i=0; i<inputNodes.length; i++){ 
     nodes.push(inputNodes[i]); 
    } 
    for(var i=0; i<inputLinks.length; i++){ 
     links.push(inputLinks[i]); 
    } 
    update(); 
} 

Cuối cùng nhanh chóng với bất cứ dữ liệu:

var layout1 = new layout1(inputNodes, inputLinks); 
var layout2 = new layout2(inputNodes, inputLinks); 

Phương pháp này có thể được áp dụng để tạo nhiều bố cục khi đang di chuyển. Hy vọng rằng đó là gần với những gì bạn đang tìm kiếm.