D3 Linking nodes based on names rather than index

后端 未结 2 671
南笙
南笙 2020-12-11 22:17

I am trying to link the nodes based on Id rather than the index in this codepen, I am not able to figure out how to do it.

The following works:

var l         


        
2条回答
  •  被撕碎了的回忆
    2020-12-11 23:11

    A D3v3 force layout doesn't support named nodes in the links. I'd suggest d3v4 or v5 if you want to use them without requiring any extra work.

    But, as with REEE's answer, you can achieve the same effect by altering your code and keeping v3. Rather than alter the tick, I'm altering the link array prior to initiating the array:

    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
    })
    

    Here's a forked plunkr, or a snippet below (I've moved your node array into its own variable - yes, it's called nodes and gets overwritten later):

    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;
    }

提交回复
热议问题