如何使用非树数据创建 d3.js 可折叠力布局? [英] How to create d3.js Collapsible force layout with non tree data?

查看:21
本文介绍了如何使用非树数据创建 d3.js 可折叠力布局?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 d3 力导向布局,其中数据的结构与下面类似.是否可以应用可折叠力布局,例如 http://bl.ocks.org/mbostock/1062288要吗?我想要一个节点在点击时折叠/展开.

I have a d3 force directed layout with data in a similar structure below. Is it possible to apply collapsible force layout such as http://bl.ocks.org/mbostock/1062288 to it? I want a node to be collapsed /expanded on click.

{
  "nodes": [
    {"x": 469, "y": 410},
    {"x": 493, "y": 364},
    {"x": 442, "y": 365},
    {"x": 467, "y": 314},
  ],
  "links": [
    {"source":  0, "target":  1},
    {"source":  1, "target":  2},
    {"source":  2, "target":  0},
    {"source":  1, "target":  3},
    {"source":  3, "target":  2},
  ]
}

推荐答案

如果我理解正确,也许这就是您要找的.我编辑了您链接的演示.现在,当一个源节点折叠起来时,我们遍历所有边并寻找它有边的其他节点.

If I understand correctly, perhaps this is what you are looking for. I edited the demo you linked to. Now when a source node is collapsed, we iterate over all edges and look for other nodes it has edges to.

对于源节点有边的每个目标节点,我们增加它的折叠计数.如果节点的折叠计数大于零,则不会显示.

for each target node that the source node has an edge to, we increment it's collapsing count. If a node has a collapsing count of greater than zero, it is not displayed.

当我们展开一个节点时,我们做同样的事情,除了我们从折叠计数中递减.

When we uncollapse a node, we do the same thing, except we decrement from the collapsing count.

我们需要这个折叠计数,因为我们不在树中,节点可以有多个节点,这会导致它们折叠.

We need this collapsing count, since, as we are not in a tree, nodes can have more than one node which should cause them to collapse.

我为有向图做了这项工作,但我不确定这是否是您想要的.

I made this work for directed graphs, though I'm not sure that's what you wanted.

告诉我你的想法!

我使用的json:

  {
    "nodes": [
     {"x": 469, "y": 410},
     {"x": 493, "y": 364},
     {"x": 442, "y": 365},
     {"x": 467, "y": 314}
 ],
     "links": [
      {"source":  0, "target":  1},
      {"source":  1, "target":  2},
      {"source":  2, "target":  0},
      {"source":  1, "target":  3},
      {"source":  3, "target":  2}
  ]
 }

修改教程代码:

<!DOCTYPE html>
<meta charset="utf-8">
<title>Force-Directed Graph</title>
<style>

.node {
  cursor: pointer;
  stroke: #3182bd;
  stroke-width: 1.5px;
}

.link {
  fill: none;
  stroke: #9ecae1;
  stroke-width: 1.5px;
}

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

var width = 960,
    height = 500,
    root;

var force = d3.layout.force()
    .size([width, height])
    .on("tick", tick);

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

//Added markers to indicate that this is a directed graph
svg.append("defs").selectAll("marker")
    .data(["arrow"])
    .enter().append("marker")
    .attr("id", function(d) { return d; })
    .attr("viewBox", "0 -5 10 10")
    .attr("refX", 15)
    .attr("refY", -1.5)
    .attr("markerWidth", 4)
    .attr("markerHeight", 4)
    .attr("orient", "auto")
    .append("path")
    .attr("d", "M0,-5L10,0L0,5");

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

d3.json("graph.json", function(json) {
  root = json;
  //Give nodes ids and initialize variables
  for(var i=0; i<root.nodes.length; i++) {
    var node = root.nodes[i];
    node.id = i;
    node.collapsing = 0;
    node.collapsed = false;
  }
  //Give links ids and initialize variables
  for(var i=0; i<root.links.length; i++) {
    var link = root.links[i];
    link.source = root.nodes[link.source];
    link.target = root.nodes[link.target];
    link.id = i;
  }

  update();
});

function update() {
  //Keep only the visible nodes
  var nodes = root.nodes.filter(function(d) {
    return d.collapsing == 0;
  });
  var links = root.links;
  //Keep only the visible links
  links = root.links.filter(function(d) {
    return d.source.collapsing == 0 && d.target.collapsing == 0;
  });

  force
      .nodes(nodes)
      .links(links)
      .start();

  // Update the links…
  link = link.data(links, function(d) { return d.id; });

  // Exit any old links.
  link.exit().remove();

  // Enter any new links.
  link.enter().insert("line", ".node")
      .attr("class", "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; })
      .attr("marker-end", "url(#arrow)");

  // Update the nodes…
  node = node.data(nodes, function(d){ return d.id; }).style("fill", color);

  // Exit any old nodes.
  node.exit().remove();

  // Enter any new nodes.
  node.enter().append("circle")
      .attr("class", "node")
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; })
      .attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
      .style("fill", color)
      .on("click", click)
      .call(force.drag);
}

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

// Color leaf nodes orange, and packages white or blue.
function color(d) {
  return d.collapsed ? "#3182bd" : d.children ? "#c6dbef" : "#fd8d3c";
}

// Toggle children on click.
function click(d) {
  if (!d3.event.defaultPrevented) {
    //check if link is from this node, and if so, collapse
    root.links.forEach(function(l) {
      if(l.source.id == d.id) {
        if(d.collapsed){
          l.target.collapsing--;
        } else {
          l.target.collapsing++;
        }
      }
    });
    d.collapsed = !d.collapsed;
  }
  update();
}

</script>

这篇关于如何使用非树数据创建 d3.js 可折叠力布局?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆