使d3强制布局与标记数据一起工作

时间:2014-10-28 02:21:23

标签: javascript d3.js label force-layout

我一直在尝试将各种d3示例中的想法粘贴到我需要的内容中,从basic example using miserable.json data开始,然后添加:

  1. 使用数据连接的关键功能
  2. 修改基础图ala this example
  3. 使链接'linkDistance()功能取决于图表链接'
  4. 的属性
  5. 向节点ala this example
  6. 添加标签

    到目前为止,我只有4个中的3个:关于使用g元素的一些事情 - 使用直接从the Mike's "Labeled Force Layout" example获取的代码 - 打破事物并且不绘制节点。如果我直接加入circle个元素,我可以使其工作,但如果我将g个元素插入附加的圆圈和文本元素,则无法使用。

    以下代码是我最好的例子。此示例有效,但如果我将.enter().append("circle")行替换为.enter().append("g")行,则无效。

    有谁知道为什么?

    var Width = 200;
    var Height = 200;
    var Pix2Len = 10;
    var color = d3.scale.category10();
    
    var svg = d3.select("body").append("svg")
    .attr("width", Width)
    .attr("height", Height);
    
    var force = d3.layout.force()
    .size([Width, Height])
    
    var graph = {
      "nodes":[
        {"name":"Myriel","idx":0},
        {"name":"Napoleon","idx":1},
        {"name":"Mlle.Baptistine","idx":2},
        {"name":"Mme.Magloire","idx":3}
      ],
      "links":[
        {"source":1,"target":0,"len":1,"idx":"1-0"},
        {"source":2,"target":1,"len":4,"idx":"2-1"},
        {"source":2,"target":0,"len":8,"idx":"2-0"},
        {"source":3,"target":0,"len":10,"idx":"3-0"},
        {"source":3,"target":1,"len":4,"idx":"3-1"},
        {"source":3,"target":2,"len":6,"idx":"3-2"}
      ]
    }
    
    console.log("data loaded. nnode="+graph.nodes.length+" nlinks="+graph.links.length);
    
    force
    .nodes(graph.nodes)
    .links(graph.links)
    .size([Width, Height])
    .linkDistance(function(link) {
        // console.log("link: "+link.source.name+' '+link.target.name+' '+link.idx+' '+link.len)
        return link.len * Pix2Len})
        .on("tick", tick);
    
    var link = svg.selectAll(".link")
    .data(graph.links, function(d)  {return d.idx; })
    .enter().append("line")
    .attr("class", "link");
    
    var node = svg.selectAll(".node")
    .data(graph.nodes, function(d) {return d.idx; })
    
    // THIS WORKS
    .enter().append("circle").attr("r", 8).style("fill", function(d) { return color(0); });
    
    // BUT THIS DOES NOT
    // modeled after http://bl.ocks.org/mbostock/950642
    //
    //.enter().append("g")
    //.attr("class", "node")
    //.attr("cx", function(d) { return d.x; })
    //.attr("cy", function(d) { return d.y; });
    //
    //node.append("circle")
    //.attr("r", 10)
    //.style("fill", function(d) { return color(0); });
    //
    //node.append("text")
    //.attr("dx", 12)
    //.attr("dy", ".35em")
    //.text(function(d) { return d.name });
    
    // 1. Begin with graph from JSON data
    setTimeout(function() {
        start();
    }, 0);
    
    // 2. Change graph topology
    setTimeout(function() {
        var new4 = {"name":"CountessdeLo","idx":4}
        var new5 = {"name":"Geborand","idx":5}
        graph.nodes.push(new4,new5);
        var link40 = {"source":4,"target":0,"len":1,"idx":"4-0"};
        var link43 = {"source":4,"target":3,"len":4,"idx":"4-3"};
        var link50 = {"source":5,"target":0,"len":1,"idx":"5-0"};
        var link52 = {"source":5,"target":2,"len":4,"idx":"5-2"};
        graph.links.push(link40,link43,link50,link52);
    
        start();
    }, 3000);
    
    //3. Change some link lengths
    
    setTimeout(function() {
    
        // force.links().forEach(function(link) {
        graph.links.forEach(function(link) {
            if (link.idx == '1-0') 
                {link.len=10; }
            else if (link.idx == '3-0') 
                {link.len=2; }
            else if (link.idx == '5-0') 
                {link.len=10; };
        }); // eo-forEach
        start();
    }, 6000);
    
    function start() {
        link = link.data(force.links(), function(d) { return d.idx; });
        link.enter().insert("line", ".node").attr("class", "link");
        link.exit().remove();
    
        node = node.data(force.nodes(), function(d) { return d.idx;});
        node.enter().append("circle").attr("class", function(d) {
        // tried with the <g> version above
    //  node.enter().append("g").attr("class", function(d) {
            console.log('start:'+' '+d.name);
            return d.idx; }).attr("r", 5).style("fill", function(d) { return color(1); });
        node.exit().remove();
    
        force.start();
    }
    
    function tick() {
        node.attr("cx", function(d) { 
            // console.log('tick:'+' '+d.name);
            return d.x; })
        .attr("cy", function(d) { return 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; });
    }
    //}  // eo-ready()
    

1 个答案:

答案 0 :(得分:2)

在您的代码中,您要将cxcy属性设置为g元素。 g元素不支持xycxcy等任何排名属性。要移动g元素的内容,您必须使用transform属性。

您的代码

var node = svg.selectAll(".node")
     .data(graph.nodes, function(d) {return d.idx; })
     .enter().append("g")
     .attr("class", "node")
     .attr("cx", function(d) { return d.x; }) //will not work
     .attr("cy", function(d) { return d.y; }); //will not work

<强>解决方案

var node = svg.selectAll(".node")
     .data(graph.nodes, function(d) {return d.idx; })
     .enter().append("g")
     .attr("class", "node");

node.append("circle")
    .attr("r", 10)
    .style("fill", function(d) { return color(0); });

node.append("text")
    .attr("dx", 12)
    .attr("dy", ".35em")
    .text(function(d) { return d.name });

使用如下的翻译功能移动组元素。

function tick() {
    //Moving <g> elements using transform attribute
    node.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; });
}

JSFiddle