修复D3强制定向布局中的节点位置

Eli*_*jah 65 javascript data-visualization d3.js force-layout d3-force-directed

我希望我的力导向布局中的一些节点忽略力并基于节点的属性保持在固定位置,同时仍然能够被拖动并在其他节点上施加排斥并保持其链接线.我觉得它会像这样简单:

force.on("tick", function() {
    vis.selectAll("g.node")
        .attr("transform", function(d) {
            return (d.someAttribute == true) ?
               "translate(" + d.xcoordFromAttribute + "," + d.ycoordFromAttribute +")" :
               "translate(" + d.x + "," + d.y + ")"
        });
  });
Run Code Online (Sandbox Code Playgroud)

我还尝试手动设置节点的x和y属性on-tick,但是如果受到力的影响,链接将继续浮动到节点所在的位置.

显然我对这应该如何工作有一个基本的误解,所以有人可以指出一个例子,其中一些节点固定在它们的位置(但仍然是可拖动的),其余的节点是围绕力导向的,并且所有链接仍在工作?

mbo*_*ock 76

d.fixed在所需节点上设置为true,并初始化d.xd.y到达所需位置.这些节点仍然是模拟的一部分,您可以使用正常的显示代码(例如,设置变换属性); 但是,因为它们被标记为固定,所以它们只能通过拖动而不是通过模拟来移动.

有关更多详细信息,请参阅force layout文档,另请参阅此示例中根节点的位置.


And*_*eid 27

固定d3v4和d4v5的强制布局节点

在d3v3 d.fixed中将修复节点d.xd.y; 但是,在d3v4/5中,不再支持此方法.在D3的文件中指出:

要在给定位置修复节点,您可以指定另外两个属性:

fx - the node’s fixed x-position

fy - the node’s fixed y-position

在每个滴答结束时,在应用任何强制之后,具有已定义node.fx的节点将node.x重置为此值并将node.vx设置为零; 同样,具有已定义node.fy的节点将node.y重置为此值,并将node.vy设置为零.要解除先前修复的节点,请将node.fx和node.fy设置为null,或删除这些属性.

您可以设置fxfy您的数据源属性的作用力节点,或者您可以添加和删除fxfy值动态.下面的代码片段在拖动事件结束时设置这些属性,只需拖动一个节点即可修复其位置:

var data ={ 
 "nodes": 
  [{"id": "A"},{"id": "B"},{"id": "C"},{"id":"D"}], 
 "links": 
  [{"source": "A", "target": "B"}, 
   {"source": "B", "target": "C"},
   {"source": "C", "target": "A"},
   {"source": "D", "target": "A"}]
}
var height = 250;
var width = 400;

var svg = d3.select("body").append("svg")
  .attr("width",width)
  .attr("height",height);
  
var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d) { return d.id; }).distance(50))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2));
    
var link = svg.append("g")
  .selectAll("line")
  .data(data.links)
  .enter().append("line")
  .attr("stroke","black");

var node = svg.append("g")
 .selectAll("circle")
 .data(data.nodes)
 .enter().append("circle")
 .attr("r", 5)
 .call(d3.drag()
   .on("drag", dragged)
   .on("end", dragended));
 
simulation
 .nodes(data.nodes)
 .on("tick", ticked)
 .alphaDecay(0);

simulation.force("link")
 .links(data.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 dragged(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;
}

function dragended(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)