简体   繁体   English

D3 4.0带有定向边和标签的图形

[英]D3 4.0 Graph with directed edges and labels

I am trying to create a graph with d3 (v4.0) that has directed edges and labels for the nodes, something like this: http://jsfiddle.net/chrisJamesC/HgHqy/ but with a newer version of D3. 我正在尝试使用d3(v4.0)创建一个图形,该图形具有针对节点的指向边和标签,如下所示: http//jsfiddle.net/chrisJamesC/HgHqy/但是使用较新版本的D3。

This is what I have so far: https://jsfiddle.net/4nu57pgn/1/ but I can't seem to figure out how to tell D3 to make the edges appear visually directed (with arrows) or to have the node IDs displayed. 这就是我到目前为止: https//jsfiddle.net/4nu57pgn/1/但我似乎无法弄清楚如何告诉D3使边缘看起来是直观的(带箭头)或者有节点ID显示。

var svg = d3.select("svg");
var width = svg.attr("width");
var height = svg.attr("height");
svg = svg.call(d3.zoom().on("zoom", zoomed)).append("g");
var color = d3.scaleOrdinal(d3.schemeCategory10);

var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d) { return d.id; }))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2));

function createGraph (error, graph) {
  if (error) throw error;

  var link = svg.append("g")
      .attr("class", "links")
    .selectAll("line")
    .data(graph.links)
    .enter().append("line")
      .attr("stroke", function(d) { return color(d.type); });


  var node = svg.append("g")
      .attr("class", "nodes")
    .selectAll("circle")
    .data(graph.nodes)
    .enter().append("circle")
      .attr("r", 10)
      .attr("fill", function(d) { if (d.root == "true") return color(d.root); return color(d.type); })
      .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended));

  node.on("click",function(d){
    console.log("clicked", d.id);
  });

  node.append("title")
      .text(function(d) { return d.id; });

  simulation
      .nodes(graph.nodes)
      .on("tick", ticked);

  simulation.force("link")
      .links(graph.links);

  function ticked() {
    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 dragstarted(d) {
  if (!d3.event.active) simulation.alphaTarget(0.3).restart();
  d.fx = d.x;
  d.fy = d.y;
}

function dragged(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;
}

function dragended(d) {
  if (!d3.event.active) simulation.alphaTarget(0);
  d.fx = null;
  d.fy = null;
}

function zoomed() {
  svg.attr("transform", "translate(" + d3.event.transform.x + "," + d3.event.transform.y + ")" + " scale(" + d3.event.transform.k + ")");
}

I am new to D3 and would appreciate any help pointing me in the correct direction. 我是D3的新手,非常感谢帮助我指明正确的方向。

Arrows 箭头

To add arrows at the end of the line you need to define a marker using SVG. 要在行尾添加箭头,您需要使用SVG定义标记。 Only slight modifications are required to update the d3 v3 code to do this with v4. 只需稍加修改即可使用v4更新d3 v3代码。 The example you provided sets up three arrow definitions (one for each type of relationship) but to create a single one you can use this: 您提供的示例设置了三个箭头定义(每种类型的关系一个),但要创建一个,您可以使用:

svg.append("defs").append("marker")
    .attr("id", "arrow")
    .attr("viewBox", "0 -5 10 10")
    .attr("refX", 20)
    .attr("refY", 0)
    .attr("markerWidth", 8)
    .attr("markerHeight", 8)
    .attr("orient", "auto")
  .append("svg:path")
    .attr("d", "M0,-5L10,0L0,5");

The values of markerWidth , markerHeight , refX , refY are significant and determine the placement of the markers - unfortunately I don't know how they interplay with the viewBox or the circle radius so these were selected by trial and error. markerWidthmarkerHeightrefXrefY是重要的,并确定标记的位置 - 遗憾的是我不知道它们如何与viewBox或圆半径相互作用,因此这些是通过反复试验选择的。

No need to capture the marker as a variable because it will be referred to using a URL specifier as follows: 无需将标记捕获为变量,因为它将使用URL说明符引用,如下所示:

  var link = svg.append("g")
      .attr("class", "links")
    .selectAll("line")
      .data(graph.links)
    .enter().append("line")
      .attr("stroke", function(d) { return color(d.type); })
      .attr("marker-end", "url(#arrow)");

Labels 标签

Again, slight modifications to the v3 code will work. 再次,对v3代码的轻微修改将起作用。 Text labels need to be appended to the SVG separately, not as children of the nodes, and translated independently in the ticked function. 文本标签需要单独附加到SVG,而不是作为节点的子项,并在ticked函数中独立翻译。

To set up the labels: 要设置标签:

var text = svg.append("g").attr("class", "labels").selectAll("g")
    .data(graph.nodes)
  .enter().append("g");

text.append("text")
    .attr("x", 14)
    .attr("y", ".31em")
    .style("font-family", "sans-serif")
    .style("font-size", "0.7em")
    .text(function(d) { return d.id; });

And then to translate them to the right location when the force simulation ticks: 然后在力模拟时将它们转换到正确的位置:

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

The horizontal offset is defined by the value of x when setting up the labels (14 in this case). 设置标签时,水平偏移量由x的值定义(在这种情况下为14)。

Together 一起

See this fiddle for the complete example. 请参阅此小提琴以获取完整示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM