繁体   English   中英

D3.js(V4)修改以组为节点的有向图

[英]D3.js (V4) Modifying Force Directed Graph with groups as nodes

我已经使用D3 V4成功创建了一个力布局图,现在正尝试添加功能,当您单击一个节点时,该功能会从图中删除,而不必每次都重新绘制该图。 我正在尝试遵循新的常规更新模式 ,当我的节点只是圆形时,我就可以使用它,但是在我的图形中,节点是包含一个圆形和两个标签的组。 当我尝试对节点进行分组并应用常规更新模式时,出现了奇怪的行为(JSFiddle)

我是D3的新手,我认为我对Enter和Exit语句或应该执行的顺序有误解。 如果你们中的任何一个可以看一下我的构建图函数并让我知道最新情况,那将很棒。

代码 (原格式,JSFiddle需要)

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>GraphViz</title>
</head>

<body name="top" class="container">
    <div class="graphPanel" style="height: 800px">
        <svg width="100%" height="100%"></svg>
    </div>
    <script
  src="https://code.jquery.com/jquery-3.2.1.min.js"
  integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
  crossorigin="anonymous"></script>
    <script
    type="text/javascript"
    src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>
    <script>
        data = {
  "nodes": [
    {
        "type": "User ID",
        "detail": "Bob Smith",
        "data": "7d7c...1e1c",
        "id": "0"
    },
    {
        "type": "Device",
        "detail": "MacOS",
        "data": "6334...1e1c",
        "id": "1"
    },
    {
        "type": "Device",
        "detail": "Windows",
        "data": "185c...1e1c",
        "id": "2"
    },
    {
        "type": "Device",
        "detail": "Windows",
        "data": "6334...1e1c",
        "id": "3"
    },
    {
        "type": "Device",
        "detail": "Android",
        "data": "6334...1e1c",
        "id": "4"
    },
    {
        "type": "Device",
        "detail": "iOS Browser",
        "data": "2312...1e1c",
        "id": "5"
    },
    {
        "type": "Shipping Address",
        "detail": "",
        "data": "San Jose, CA 95113",
        "id": "6"
    },
    {
        "type": "Account Name",
        "detail": "",
        "data": "4d6f....aa10",
        "id": "7"
    },
    {
        "type": "Account Login",
        "detail": "",
        "data": "bsmith",
        "id": "8"
    },
    {
        "type": "Credit Card Hash",
        "detail": "",
        "data": "1cca...81e1",
        "id": "9"
    },
    {
        "type": "SSN",
        "detail": "",
        "data": "4fed...3er5",
        "id": "10"
    },
    {
        "type": "Account Number",
        "detail": "",
        "data": "78945648",
        "id": "11"
    },
    {
        "type": "Email",
        "detail": "",
        "data": "bob@bobsmith.com",
        "id": "12"
    }
  ],
  "links": [
    {
        "source": "0",
        "target": "1",
        "id": "0"
    },
    {
        "source": "0",
        "target": "2",
        "id": "1"
    },
    {
        "source": "0",
        "target": "3",
        "id": "2"
    },
    {
        "source": "0",
        "target": "4",
        "id": "3"
    },
    {
        "source": "0",
        "target": "5",
        "id": "4"
    },
    {
        "source": "0",
        "target": "6",
        "id": "5"
    },
    {
        "source": "0",
        "target": "7",
        "id": "6"
    },
    {
        "source": "0",
        "target": "8",
        "id": "7"
    },
    {
        "source": "0",
        "target": "9",
        "id": "8"
    },
    {
        "source": "0",
        "target": "10",
        "id": "9"
    },
    {
        "source": "0",
        "target": "11",
        "id": "10"
    },
    {
        "source": "0",
        "target": "12",
        "id": "11"
    }
  ]
}

    buildGraph(data.links, data.nodes);

  function buildGraph(links, nodes) {
    var svg = d3.select("svg"),
    width = $("svg").width(),
    height = $("svg").height(),
    color = d3.scaleOrdinal(d3.schemeCategory10);

    var simulation = d3.forceSimulation(nodes)
    .force("charge", d3.forceManyBody().strength(-1000))
    .force("link", d3.forceLink(links).distance(200))
    .force("x", d3.forceX())
    .force("y", d3.forceY())
    .alphaTarget(1)
    .on("tick", ticked);

    var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"),
    link = g.append("g").attr("stroke", "#000").attr("stroke-width", 1.5).selectAll(".link"),
    node = g.append("g").attr("stroke", "#000").attr("stroke-width", 1.5).selectAll(".node");

    var circle, label, data;

    restart();

    function restart() {

      node = node.data(nodes, function(d) { return d.id;});
      node.exit().remove();
      node = node.enter().append("g")
      .merge(node);

      circle = node.append("circle")
      .attr("fill", function(d) { return color(d.id); }).attr("r", 8)
      .attr("id", function(d){return d.id;})
      .call(d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended));

      link = link.data(links, function(d) { return d.source.id + "-" + d.target.id; });
      link.exit().remove();
      link = link.enter().append("line")
      .attr("id", function(d) {
        return d.source + "-" + d.target;
      })
      .merge(link);

      label = node.append("text")
      .attr("font-size", "15")
      .attr("font-weight", "bold")
      .attr("class", "nodeLabel")
      .html(function(d) { 
        var detail = d.detail === "" ? "" : ": " + d.detail;
        return d.type + detail;
      });

      data = node.append("text")
      .html(function(d) { 
        return d.data;
      })
      .attr("class", "nodeLabel");

      simulation.nodes(nodes);
      simulation.force("link").links(links);
      simulation.alpha(1).restart();
    }

    $("circle").click(function() {
      console.log(links)
      $("circle").removeClass("selected");
      d3.select(this).classed("selected", true);
      var id = $(this).attr("id");
      nodes.forEach(function(thisNode) {
        if (thisNode.id === id) {
          var index = nodes.indexOf(thisNode);
          nodes.splice(index, 1);
        }
      });
      for(var i = links.length - 1; i >=0; i--) {
        if(links[i].target.id === id || links[i].source.id === id) {
          links.splice(i, 1);
        }
      }
      restart();
    });

    function ticked() {
      node.attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; })

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

      circle
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; });

      label
      .attr("x", function(d) { return d.typeCode === "did" ? d.x + 35 : d.x + 25; })
      .attr("y", function(d) { return d.y; });

      data
      .attr("x", function(d) { return d.typeCode === "did" ? d.x + 35 : d.x + 25; })
      .attr("y", function(d) { return d.y + 15; });
    }

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

    </script>
</body>

</html>

我正在更改我以前的答案,因为它完全错误,请查看此链接: 在此处输入链接描述 ,这样可以使您一切正常。 而且我仍然对您的删除事件绑定到圈子保持一致,您必须将其绑定到您的节点()

暂无
暂无

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

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