D3根据名称而不是索引链接节点

时间:2018-07-17 20:44:21

标签: javascript d3.js

我试图基于Id而不是基于此codepen中的索引来链接节点,所以我不知道该怎么做。

以下作品:

var links = [{ source:  0, target: 1 }];

但是,如果我基于名称创建链接,则不会创建任何链接。

var links = [{ source: "FH" , target: "TP"  }];

2 个答案:

答案 0 :(得分:5)

D3v3强制布局不支持链接中的命名节点。如果您想使用它们而不需要任何额外的工作,我建议使用d3v4或v5。

但是,与REEE的答案一样,您可以通过更改代码并保留v3来达到相同的效果。我没有更改刻度,而是在启动数组之前更改了link数组:

var obj = {}
nodes.forEach(function(d,i){
  obj[d.id] = i;             // create an object to look up a node's index by id
})

links.forEach(function(d) {
  d.source = obj[d.source];  // look up the index of source
  d.target = obj[d.target];  // look up the index of target
})

这是一个分叉的plunkr或下面的代码片段(我将您的节点数组移到了自己的变量中-是的,它称为节点,以后会被覆盖):

var width = 500,
  height = 200;

var fill = d3.scale.category20();
var links = [{ source:  "FH", target: "TP" }];
var nodes = [
    { id: "FH", x: 100, y: 110 },
    { id: "TP", x: 200, y: 110 },
    { id: "GW", x: 200, y: 110 },
    { id: "DB", x: 100, y: 110 }
  ]

var obj = {}
nodes.forEach(function(d,i){
  obj[d.id] = i;
})

links.forEach(function(d) {
  d.source = obj[d.source];
  d.target = obj[d.target];
})

var force = d3.layout
  .force()
  .size([width, height])
  .nodes(nodes)
  .links(links)
  .linkDistance(150)
  .charge(-500)
  .on("tick", tick);

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

var arrows = svg
  .append("svg:defs")
  .selectAll("marker")
  .data(["arrow"])
  .enter()
  .append("marker")
  .attr("id", String)
  .attr("viewBox", "0 -5 10 10")
  .attr("refX", 15)
  .attr("refY", -1.5)
  .attr("markerWidth", 6)
  .attr("markerHeight", 6)
  .attr("orient", "auto")
  .append("path")
  .attr("d", "M0,-5L10,0L0,5");

svg
  .append("rect")
  .attr("width", width)
  .attr("height", height);

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

restart();





function tick() {
  link.attr("d", function(d) {
    var dx = d.target.x - d.source.x,
      dy = d.target.y - d.source.y,
      dr = Math.sqrt(dx * dx + dy * dy);
    return (
      "M" +
      d.source.x +
      "," +
      d.source.y +
      "A" +
      dr +
      "," +
      dr +
      " 0 0,1 " +
      d.target.x +
      "," +
      d.target.y
    );
  });

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

function restart() {
  node = node.data(nodes);
  node
    .enter()
    .insert("g")
    .attr("class", "node")
    .call(force.drag);
  node
    .append("image")
    .attr("xlink:href", "https://github.com/favicon.ico")
    .attr("x", -8)
    .attr("y", -8)
    .attr("width", 16)
    .attr("height", 16);
  node
    .append("text")
    .attr("dx", 12)
    .attr("dy", ".35em")
    .text(function(d) {
      return d.id;
    });
  node.exit().remove();

  link = link.data(links);
  link
    .enter()
    .append("path")
    .attr("class", "link")
    .attr("marker-end", "url(#arrow)");
  link.exit().remove();

  force.start();
}
#nodeConsole {
  width: 80%;
  height: 1px;
  font-family: courier new;
  padding: 1px;
  border: 3px solid gray;
  margin-top: 1px;
  overflow: autao;
}

#linkedNodes {
  width: 80%;
  font-family: courier new;
  padding: 10px;
}

#srcNodes {
  width: 40%;
  font-family: courier new;
  padding: 8px;
}

#targetNodes {
  width: 40%;
  font-family: courier new;
  padding: 8px;
}

rect {
  fill: none;
  pointer-events: all;
}

.node {
  fill: #000;
}

.cursor {
  fill: none;
  stroke: brown;
  pointer-events: none;
}

.link {
  stroke: #999;
}
.node text {
  pointer-events: none;
  font: 10px sans-serif;
}

path.link {
  fill: none;
  stroke: #666;
  stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

答案 1 :(得分:1)

您可以这样操作:https://codepen.io/anon/pen/yqJoje?editors=0011

我基本上过滤节点数组,以查找与目标和源有关的x和y数据,然后将它们分配给一个值,以供您进行路径分配。相关代码在这里:

function tick() {
  link.attr("d", function(d) {
    var curData = {
      target: nodes.filter(function (n) {
                if (n.id == d.target) {
                  return { x: d.x, y: d.y };
                }
              })[0],
      source: nodes.filter(function (n) { 
                if (n.id == d.source) {
                  return { x: d.x, y: d.y };
                }
              })[0]
    };
           ...
           ...
}

注意:不确定在tick函数中通过数组过滤是否是一个好主意,因为如果生成大量节点,可能会导致性能下降。滴答功能被称为很多。