program story

D3 Force Directed Layout에서 노드 위치 수정

inputbox 2020. 11. 18. 09:01
반응형

D3 Force Directed Layout에서 노드 위치 수정


내 힘 지향 레이아웃의 일부 노드가 모든 힘을 무시하고 노드의 속성에 따라 고정 된 위치에 머무르면서 다른 노드에 대해 끌고 반발력을 발휘하고 링크 라인을 유지할 수 있기를 바랍니다.

다음과 같이 간단 할 것이라고 생각했습니다.

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

또한 각 틱마다 노드의 x 및 y 속성을 수동으로 설정하려고 시도했지만 힘의 영향을받는 경우 링크가 노드가있는 위치로 계속 떠 다닙니다.

분명히 이것이 어떻게 작동 해야하는지에 대한 기본적인 오해가 있습니다. 링크를 유지하면서 드래그 할 수 있도록 허용하면서 위치에서 노드를 수정하려면 어떻게해야합니까?


설정 d.fixedtrue로 원하는 노드에서, 초기화 d.xd.y원하는 위치로. 이러한 노드는 여전히 시뮬레이션의 일부가되며 일반 디스플레이 코드를 사용할 수 있습니다 (예 : 변환 속성 설정). 그러나 고정 된 것으로 표시되어 있기 때문에 시뮬레이션이 아닌 드래그로만 이동할 수 있습니다.

자세한 내용은 강제 레이아웃 문서 ( v3 문서 , 현재 문서 )를 참조 하고이 예제 에서 루트 노드의 위치를 ​​확인 하십시오 .


d3v4 및 d4v5에 대한 강제 레이아웃의 고정 노드

d3v3 d.fixed에서 d.x노드를 수정합니다 d.y. 그러나 d3v4 / 5에서는이 방법이 더 이상 지원되지 않습니다. D3 문서 상태 :

주어진 위치에서 노드를 수정하려면 두 가지 추가 속성을 지정할 수 있습니다.

fx - the node’s fixed x-position

fy - the node’s fixed y-position

각 틱이 끝날 때 힘을 적용한 후 node.fx가 정의 된 노드는 node.x를이 값으로 재설정하고 node.vx를 0으로 설정합니다. 마찬가지로 node.fy가 정의 된 노드는 node.y를이 값으로 재설정하고 node.vy를 0으로 설정합니다. 이전에 수정 된 노드를 수정 해제하려면 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;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.min.js"></script>

참고 URL : https://stackoverflow.com/questions/10392505/fix-node-position-in-d3-force-directed-layout

반응형