动态添加节点后如何自动缩放我的 Dagre 图?

问题描述

My JsFiddle 使用优秀的 Dagre 动态创建网络图。完整代码如下,以满足发帖要求。

我的问题是,当我添加节点时,我无法让它自动缩放以使节点适合图形(的 SVG 画布)。

enter image description here

添加几个节点,然后...

enter image description here

如何在添加新节点后自动缩放以适应?

嗯,经过一定程度的缩放后,可能会变得难以阅读,所以我想我应该在一定程度后限制缩放并将其留给用户滚动,而不是所有时间都可以看到所有图形( ?).

如果只有 Dagre 处理这个(和自动布局(我强烈希望将一个节点居中,将其锁定在中心并让其他节点出现在它周围 - 我不关心排序,但某种形式的权重,虽然不是绝对必要的,但不会伤害))。想,也许我使用了错误的库,但搜索,甚至 a quarion on S/W reccomendations 都没有帮助,而 Dagre 在其他方面非常出色。

好了,我离题了。以及如何让它自动缩放?


这是 HTML:

<!doctype html>
<headd>
<Meta charset="utf-8">
<title>Dynamic social network</title>

<link rel="stylesheet" href="style.css">
<script src="https://d3js.org/d3.v5.min.js" charset="utf-8"></script>
<script src="https://dagrejs.github.io/project/dagre-d3/latest/dagre-d3.js"></script>
</head>

<body>

<!-- based loosely on https://dagrejs.github.io/project/dagre-d3/latest/demo/clusters.html -->
<!-- docs at https://npmdoc.github.io/node-npmdoc-dagre/build/apidoc.html-->

<h1>Social network demo</h1>

<style id="css">
.clusters rect {
  fill: whitesmoke;
  stroke: #999;
  stroke-width: 1.5px;
  margin: auto;
}

text {
  font-weight: 300;
  font-family: "Helvetica Neue",Helvetica,Arial,sans-serf;
  font-size: 14px;
}

.node rect {
  stroke: #999;
  fill: #fff;
  stroke-width: 1.5px;
}

.edgePath path {
  stroke: #333;
  stroke-width: 1.5px;
}
</style>

<a href="javascript:AddGroup()">Add a group</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="javascript:AddPerson()">Add a person (to a random group,at a random level)</a>
<br>
<br>

<svg id="svg-canvas" width=600 height=6000></svg>

<script id="js">
  // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
  let forenames = [];
  forenames.push("Michael");
  forenames.push("David");
  forenames.push("John");
  forenames.push("James");
  forenames.push("Robert");
  forenames.push("Mark");
  forenames.push("William");
  forenames.push("Richard");
  forenames.push("Thomas");
  forenames.push("Jeffrey");
  forenames.push("Steven");
  forenames.push("Joseph");
  forenames.push("Timothy");
  forenames.push("Kevin");
  forenames.push("Scott");
  forenames.push("Brian");
  forenames.push("Charles");
  forenames.push("Paul");
  forenames.push("Daniel");
  forenames.push("Christopher");
  forenames.push("Anthony");
  forenames.push("Kenneth");
  forenames.push("Gregory");
  forenames.push("Ronald");
  forenames.push("Donald");
  forenames.push("Lisa");
  forenames.push("Mary");
  forenames.push("Susan");
  forenames.push("Karen");
  forenames.push("Margaret");
  forenames.push("Patricia");
  forenames.push("Linda");
  forenames.push("Donna");
  forenames.push("Michelle");
  forenames.push("Cynthia");
  forenames.push("Sandra");
  forenames.push("Deborah");
  forenames.push("Tammy");
  forenames.push("Pamela");
  forenames.push("Christine");
  forenames.push("Laura");
  forenames.push("Elizabeth");
  forenames.push("Julie");
  forenames.push("Brenda");
  forenames.push("Jennifer");
  forenames.push("Barbara");
  forenames.push("Angela");
  forenames.push("Sharon");
  forenames.push("Debra");
  forenames.push("Teresa");

  // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
  let surnames = [];
  surnames.push("Smith");
  surnames.push("Jones");
  surnames.push("Williams");
  surnames.push("Taylor");
  surnames.push("brown");
  surnames.push("Davies");
  surnames.push("Evans");
  surnames.push("Wilson");
  surnames.push("Thomas");
  surnames.push("Johnson");
  surnames.push("Roberts");
  surnames.push("Robinson");
  surnames.push("Thompson");
  surnames.push("Wright");
  surnames.push("Walker");
  surnames.push("White");
  surnames.push("Edwards");
  surnames.push("Hughes");
  surnames.push("Green");
  surnames.push("Hall");
  surnames.push("Lewis");
  surnames.push("Harris");
  surnames.push("Clarke");
  surnames.push("Jackson");
  surnames.push("Wood");
  surnames.push("Turner");
  surnames.push("Martin");
  surnames.push("Cooper");
  surnames.push("Hill");
  surnames.push("Ward");

  const initalNodeName = 'Hiro protaganist';
  let groupNumber = 0;
  let lastAddedGroupName = '';
  
  // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
  function Rendergraph()
  {
      // Round the corners of the nodes
      g.nodes().forEach(function(v) {
      let node = g.node(v);
      node.rx = node.ry = 5;
    });
    
    // Run the renderer. This is what draws the final graph.
    render(d3.select("svg g"),g);

    // Set up an SVG group so that we can translate the final graph.
    let svg = d3.select("svg"),svgGroup = svg.append("g");

    // Center the graph
    let xCenterOffset = (svg.attr("width") - g.graph().width) / 2;
    svgGroup.attr("transform","translate(" + xCenterOffset + ",20)");
    svg.attr("height",g.graph().height + 40);    


    let selections = inner.selectAll("g.node");
    selections
        .on('mouSEOver',function(d) {
          console.log('mouSEOver ' + d);
        })
        // .on('mouSEOut',function(d) {
        //   console.log('mouSEOut ' + d);
        // })
        // .on('mousedown',function(d) {
        //   console.log('mousedown ' + d);
        // })
        // .on('mouseup',function(d) {
        //   console.log('mouseup ' + d);
        // })
        .on('click',function (d) {
          alert('You clicked "' + d + '"'); 
        });
  }

  // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
  function AddGroup()
  {
    let groupName = 'Group_' + ++groupNumber;
    lastAddedGroupName = groupName;
    console.log('Added ' + groupName);
    g.setNode(groupName,{ label: groupName,clusterLabelPos: 'bottom' });
    Rendergraph();
  }

  // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
  function AddPerson()
  {
    let numChildrenInGroup = 0;

    if (groupNumber === 0)  // No groups,so create one,to add the new person to
    {
      AddGroup();
    }
    else
    {
      numChildrenInGroup = g.children(lastAddedGroupName).length;

      // 1 chance in 4 to add a new group & switch to that
      if ((Math.floor(Math.random() * 4) + 1) === 1)
      {    
        AddGroup();
        numChildrenInGroup = g.children(lastAddedGroupName).length;
      }
      else
      {
        if (numChildrenInGroup == 4)
        {
          AddGroup();
          numChildrenInGroup = 0;
        }
      }
    }

    let forname = forenames[Math.floor(Math.random() * forenames.length)];
    let suname  = surnames[Math.floor(Math.random() * surnames.length)];
    let name    = forname + ' ' + suname;

    let level = 1;   // FixMe:
    if (numChildrenInGroup > 0)
    {
      level = Math.floor(Math.random() * 2) + 1;
    }

    let borderColour = 'green';
    if (level === 2)
      borderColour = 'blue';

    g.setNode(name,{label: name,style: 'stroke: ' + borderColour,level: level});
    g.setParent(name,lastAddedGroupName);
    
    g.setEdge(initalNodeName,name,{ arrowhead: 'undirected',label: level} );

    console.log('Added ' + name);
    Rendergraph();
  }   // AddPerson()

  // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
  // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=

  // Create the input graph
  let g = new dagreD3.graphlib.Graph({compound:true})
    .setGraph({})
    .setDefaultEdgeLabel(function() { return {}; });

   // Here we're setting the initial,central node
  g.setNode(initalNodeName,{label: initalNodeName,style: 'stroke: red',level: 2});

  // Create the renderer
  let render = new dagreD3.render();

  // // Set up an SVG group so that we can translate the final graph.
  let svg = d3.select("svg"),inner = svg.append("g");

// Todo: Look at https://github.com/dagrejs/dagre-d3/issues/144          
// // Set up zoom support
// let zoom = d3.behavior.zoom().on("zoom",function() {
//     inner.attr("transform","translate(" + d3.event.translate + ")" +
//                                 "scale(" + d3.event.scale + ")");
//   });
// svg.call(zoom);

  Rendergraph();

</script>

</body>
</html>

这里是 CSS:

body {
  width: 960px;
  margin: 0 auto;
  color: #333;
  font-weight: 300;
  font-family: "Helvetica Neue",sans-serf;
}

h1 {
  font-size: 3em;
  font-weight: 300;
}

h2 {
  font-size: 1.5em;
  font-weight: 300;
}

section {
  margin-bottom: 3em;
}

section p {
  text-align: justify;
}

svg {
  border: 1px solid #ccc;
  overflow: hidden;
  margin: 0 auto;
}

pre {
  border: 1px solid #ccc;
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)