2

我正在尝试在 d3.js 中构建一个有向力图,它上面有一个点击监听器,可以更改基础数据并重绘图形。我相信我正在遵循 Bostock 先生的更新模式,但我遇到的问题是,当我运行由点击侦听器触发的更新时,节点会从屏幕底部消失,留下链接和标签。

此更新似乎正在运行,更新现有节点(在这种情况下将它们变为绿色)然后忽略“进入”和“退出”部分(这是所需的行为)然后点击将节点发送到南方的 tick() 函数。

我可以通过删除节点上的“g”标签来实现这个工作,从而将标签和节点解耦,这显然是不可取的。

我不禁觉得我错过了一些明显的东西!或者也许我应该以不同的方式解决这个问题?

这是代码:

var width = 960,
    height = 500,
    links,
    nodes,
    root;

var force = d3.layout.force()
    .size([width, height])
    .charge(-200)
    .linkDistance(50)
    .on("tick", tick);

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

var link = svg.selectAll(".link"),
    node = svg.selectAll(".node");

d3.json("test.json", function(json) {
  root = json;
  update();
});

function update() {
  nodes = root.nodes
  links = root.links

  // Restart the force layout.
  force
      .nodes(nodes)
      .links(links)
      .start();

    svg.append("svg:defs").append("marker")
        .attr("id", "end")
        .attr("refX", 15)
        .attr("refY", 2)
        .attr("markerWidth", 6)
        .attr("markerHeight", 4)
        .attr("orient", "auto")
        .append("svg:path")
        .attr("d", "M 0,0 V 4 L8,2 Z");

  // Update the links…
  //link = link.data(links, function(d) { return d.target.name; });
  link = link.data(links)

  // Exit any old links.
  link.exit().remove();

  // Enter any new links.
  link.enter().insert("svg:line", ".node")
      .attr("class", "link")
      .attr("marker-end", "url(#end)")
      .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; });

  // Update the nodes…
  node = svg.selectAll("g").select(".node").data(nodes, function(d) { return d.name; });


  node.style("fill", "green")

  // Exit any old nodes.
  node.exit().remove();

  // Enter any new nodes.
  node.enter().append("g")
      .append("svg:circle")
      .attr("class", "node")
      .attr("id", function(d) {return "node" + d.index; })
      .attr("r", 12)
      .style("fill", "#BBB")
      .on("click", click)
      .call(force.drag);

  node.append("svg:text")
      .attr("dx", 16)
      .attr("dy", ".15em")
      .attr("class", "nodelabel")
      .text(function(d) { return d.name });
}

function tick() {
  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; });

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

}


function click(d) {
  if (!d3.event.defaultPrevented) {

    // DO ANYTHING
    update()
  }
}

test.json 的内容是:

{
  "nodes": [
    {"name" : "John"},
    {"name" : "Alison"},
    {"name" : "Phil"},
    {"name" : "Jim"},
    {"name" : "Jane"},
    {"name" : "Mary"},
    {"name" : "Joe"}
  ],
  "links": [
    {"source":  1, "target":  0},
    {"source":  2, "target":  0},
    {"source":  3, "target":  0},
    {"source":  4, "target":  0},
    {"source":  5, "target":  1},
    {"source":  6, "target":  1}
  ]
}
4

1 回答 1

1

好的,所以我发现了问题所在。当我选择要更新的节点时,我正在选择节点(即具有类“节点”的元素)并且它们正在被更新:

node = svg.selectAll("g").select(".node").data(nodes, function(d) { return d.name; });

然后在 tick 函数中,我正在更新这些节点:

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

所以这是完全正确的,但是,节点与文本标签一起被封装在“g”标签中,但tick()函数只作用于节点。修复是强制转换属性tick()更新整个组,而不仅仅是节点:

svg.selectAll("g").attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

现在一切正常!

于 2013-10-11T09:24:14.370 回答