如何动态添加到d3拓扑的链接?

时间:2014-10-17 11:44:10

标签: javascript d3.js

我使用sticky force layout示例并尝试添加额外的链接并使用enter()更新布局,但随后所有链接都消失了,FireBug也没有显示任何错误。

这些行是否已添加链接?
graph.links.push({"source": 0, "target": 11});
link = link.data(graph.links).enter().append("line").attr("class", function(d,i) {console.log(i);return "link";});

此外,console.log(i)输出18代替19。它似乎从未考虑过graph数组大小的增加。

我检查了this example,但即使在这里,使用data()enter()功能似乎已经足够了。

代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.link {
  stroke: #000;
  stroke-width: 1.5px;
}

.node {
  cursor: move;
  fill: #ccc;
  stroke: #000;
  stroke-width: 1.5px;
}

.node.fixed {
  fill: #f00;
}

</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>

var graph =
{
  "nodes": [
    {"x": 469, "y": 410},
    {"x": 493, "y": 364},
    {"x": 442, "y": 365},
    {"x": 467, "y": 314},
    {"x": 477, "y": 248},
    {"x": 425, "y": 207},
    {"x": 402, "y": 155},
    {"x": 369, "y": 196},
    {"x": 350, "y": 148},
    {"x": 539, "y": 222},
    {"x": 594, "y": 235},
    {"x": 582, "y": 185},
    {"x": 633, "y": 200}
  ],
  "links": [
    {"source":  0, "target":  1},
    {"source":  1, "target":  2},
    {"source":  2, "target":  0},
    {"source":  1, "target":  3},
    {"source":  3, "target":  2},
    {"source":  3, "target":  4},
    {"source":  4, "target":  5},
    {"source":  5, "target":  6},
    {"source":  5, "target":  7},
    {"source":  6, "target":  7},
    {"source":  6, "target":  8},
    {"source":  7, "target":  8},
    {"source":  9, "target":  4},
    {"source":  9, "target": 11},
    {"source":  9, "target": 10},
    {"source": 10, "target": 11},
    {"source": 11, "target": 12},
    {"source": 12, "target": 10}
  ]
};

var width = 960,
    height = 500;

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

var drag = force.drag()
    .on("dragstart", dragstart);

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

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

//d3.json("graph.json", function(error, graph) {

  force.nodes(graph.nodes).links(graph.links).start();
  link = link.data(graph.links).enter().append("line").attr("class", "link");

  node = node.data(graph.nodes)
    .enter().append("circle")
      .attr("class", "node")
      .attr("r", 12)
      .on("dblclick", dblclick)
      .call(drag);
//});

console.log(graph.links.length);
graph.links.push({"source": 0, "target": 11});
console.log(graph.links.length);
link = link.data(graph.links).enter().append("line").attr("class", "link");


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("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; });
}

function dblclick(d) {
  d3.select(this).classed("fixed", d.fixed = false);
}

function dragstart(d) {
  d3.select(this).classed("fixed", d.fixed = true);
}

</script>

1 个答案:

答案 0 :(得分:1)

主要问题是

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

在此之后,link将仅包含您在使用.enter()时刚刚添加到可视化中的链接。这反过来意味着只有那些将在力布局的tick事件期间更新,因为您在那里使用相同的link变量。 node也是同样的问题。

要修复,请在添加新元素后将选择变量设置为包含所有相关元素。

link = svg.selectAll(".link");

完整演示here