javascript - 使 d3 强制布局与标记数据一起使用

标签 javascript d3.js label force-layout

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

  1. 使用关键函数进行数据连接
  2. 修改底层图表 ala this example
  3. 使链接的 linkDistance() 函数依赖于图表链接的属性
  4. 向节点添加标签 ala this example

到目前为止,我只有 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()

最佳答案

在您的代码中,您将 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

关于javascript - 使 d3 强制布局与标记数据一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26599918/

相关文章:

ios - 以编程方式创建多个标签变量

html - 标签被以下元素溢出

javascript - 无论单击“确定”还是“取消”,我的确认弹出窗口仍在删除对象。为什么? Angular 怪?

javascript - 获取层未定义

javascript - 背景图片不是通过javascript添加的

javascript - d3js缩放+拖动导致冲突

javascript - 如何读取 Json 文件并将一些数据存储在数组中,然后在读取文件后访问它?

javascript - 如何使用socket.io请求实现类似jQuery的回调?

javascript - 向 D3 中的现有 map 添加新路径

python - 如何在Python Tkinter中管理带边框标签内的间距?