2016-10-04 2 views
3

d3 force 시뮬레이션 (버전 4에서!)에 하나씩 노드를 추가하려고하는데, 일부는 생성 된 후에 시뮬레이션에 의해 진화 된 것으로 보이지 않습니다 . d3 v4 동적으로 추가 된 노드에 작용하는 힘


현재 시뮬레이션은 함수, addNode 명 두 번 두 개 이상의 노드를 추가라고 한 노드를 할당합니다. 각각은 시뮬레이션에 추가되고 원과 선이 렌더링되고 커서 이벤트가 하나씩 추가됩니다.

노드를 클릭하면,

다음 새 노드 (기술적으로는 제 1 및 제 2 노드는 제만을위한 addNode 제 2 호출 될 때 설정되는 한, 동시에 수행된다) 연결된 커서 아래에있는 아이콘을 생성해야합니다. 이 노드는 시뮬레이션과 마찬가지로 다른 노드와 마찬가지로 진화해야합니다.


그러나, 일 동안 또는 두 개의 노드가 잘 만든 것 같다, 나중에 노드는 시뮬레이션에서 진화 할 것 같지 않습니다. 특히 노드 사이에 약간의 간격을 유지해야하는 많은 본문 강제는 작동하지 않는 것 같습니다.


내 직감 (일부 simulation.stop을 추가하여 이전 문제가 해결되었고 simulation.restart 새로운 노드가 추가되고 있었다 언제든지 명령) 노드가 시뮬레이션의 쳤다 기능에 대한 부적당 한 번에 추가되는 것입니다하지만, 이론적으로 시뮬레이션은 새로운 바디가 추가 될 때마다 일시 정지되어야합니다.

d3 v4에서 노드를 동적으로 추가하는 올바른 구현입니까, 아니면 맹 글링 된 메소드를 강조 표시하는 것의 문제입니까? This 이전 답변은 새로운 항목을 병합해야한다는 것을 깨닫도록 도와 주었지만, 힘이 거기에서 잘 작동하는 것처럼 보입니다. 도에

var w = 250; 
 
var h = 250; 
 

 
var svg = d3.select("body").append("svg"); 
 

 
svg.attr('width', w) 
 
    .attr('height', h); 
 

 
// ensures links sit beneath nodes 
 
svg.append("g").attr("id", "lnks") 
 
svg.append("g").attr("id", "nds") 
 

 
function new_node(id) { 
 
    this.id = id; 
 
    this.x = w/2; 
 
    this.y = h/2; 
 
} 
 

 
function new_link(source, target) { 
 
    this.source = source; 
 
    this.target = target; 
 
} 
 

 
var nodes = []; 
 
var links = []; 
 

 
var node; 
 

 
var circles; 
 

 
var link; 
 

 
var simulation = d3.forceSimulation() 
 
    .force("link", d3.forceLink().distance(80).id(function(d) { 
 
    return d.id; 
 
    })) 
 
    .force("charge", d3.forceManyBody().strength(-1000)) 
 
    .force("xPos", d3.forceX(w/2)) 
 
    .force("yPos", d3.forceY(h/2)) 
 
    .on('tick', ticked); 
 

 
simulation.stop(); 
 

 
var newNode = new new_node(0); 
 
nodes.push(newNode); 
 

 
for (var i = 1; i < 3; i++) { 
 
    if (i == 3) continue; 
 
    addNode(0, i) 
 
} 
 

 
function addNode(rootId, newId) { 
 

 
    var newNode = new new_node(newId); 
 
    nodes.push(newNode); 
 
    var newLink = new new_link(rootId, newId); 
 
    links.push(newLink); 
 

 
    //adds newest link and draws it 
 
    link = svg.select("#lnks").selectAll(".link") 
 
    .data(links) 
 
    var linkEnter = link 
 
    .enter().append("line") 
 
    .attr("class", "link"); 
 
    link = linkEnter.merge(link); 
 

 
    //adds newest node 
 
    node = svg.select("#nds").selectAll(".node") 
 
    .data(nodes) 
 
    var nodeEnter = node 
 
    .enter().append("g") 
 
    .attr("class", "node"); 
 

 
    //draws circle on newest node 
 
    var circlesEnter = nodeEnter.append('circle') 
 

 
    node = nodeEnter.merge(node); 
 
    circles = d3.selectAll('circle'); 
 

 
    simulation.stop(); 
 

 
    simulation.nodes(nodes); 
 

 
    simulation.force("link") 
 
    .links(links); 
 

 
    restartSim(); 
 
} 
 

 
//starts up the simulation and sets up the way the leaves react to interaction 
 
function restartSim() { 
 
    simulation.restart(); 
 

 
    circles.on('click', function(d, i) { 
 
    addNode(i, nodes.length) 
 
    }) 
 
} 
 

 
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("transform", function(d) { 
 
    return "translate(" + d.x + "," + d.y + ")"; 
 
    }); 
 
}
.link { 
 
    stroke: #bbb; 
 
} 
 
.node circle { 
 
    pointer-events: all; 
 
    fill: black; 
 
    stroke-width: 0px; 
 
    r: 20px 
 
} 
 
h1 { 
 
    color: white; 
 
}
<script src="https://d3js.org/d3.v4.min.js"></script>

코드는 여기 codepen : http://codepen.io/zpenoyre/pen/kkxBRW?editors=0010

답변

4

힘 시뮬레이션을 이름이 서로 상호 작용하는 입자에 대한 시뮬레이션이 있듯이. 알파는 반복 할 때마다 썩어서 시스템을 수렴하는 데 사용됩니다. 힘은 알파로 곱해 지므로 각 반복에서 시뮬레이션이 멈 추면 알파가 매우 낮은 값에 도달 할 때까지 힘이 약 해집니다. D3 문서에서 :

simulation.restart() <>

다시 시작 시뮬레이션의 내부 타이머 및 시뮬레이션을 반환합니다. simulation.alphaTarget 또는 simulation.alpha와 함께이 메소드는 노드를 끌 때와 같이 상호 작용 중 시뮬레이션을 "재가열"( )하거나 시뮬레이션 후 일시적으로 시뮬레이션을 재개하는 데 사용할 수 있습니다. 시뮬레이션으로 일시 중지합니다.

노드를 추가 할 때 시뮬레이션이 이미 중지되었으므로 시뮬레이션을 알파 1로 "재가열"해야합니다., 고맙다 잘 작동 http://codepen.io/anon/pen/amqrWq?editors=0010

+0

: 여기

simulation.force("link") .links(links); simulation.alpha(1); // <---- reheat; restartSim(); 

업데이트 된 코드 펜입니다. 알파가 여기서 무엇을하는지 이해하는 간단한 방법이 있습니까? "Reheating"은 나에게 매우 직관적이지 않으며 [d3 API] (https://github.com/d3/d3-force/blob/master/README.md#simulation_alpha)는 나에게별로 의미가 없습니다. 주제에. – Zephyr

+0

굉장 해요, 나는 시뮬레이션을 효과적으로 피터 밖으로 깨닫지 못했지만, 그것들을 자세히 보면서 나는 그것을 아주 분명하게 본다. 시뮬레이션 계산을 줄이고 싶지만 설정을 변경할 때마다 시뮬레이션을 다시 시작해야합니다. 감사! – Zephyr

+0

@Zephyr 두 번째 코멘트에서 알 수 있습니다. 그러나'simulation.alphaTarget' 커밋에서 여러분이나 다른 누군가에게 좋은 추가 정보가 있습니다 : (https://github.com/d3/d3-force/commit/8a2c8590bb879c70eb2e10264b41d0200c887be9) "이것으로"원하는 "알파를 설정할 수 있습니다. 시뮬레이션을 수행하고 시뮬레이션을 원하는 값으로 부드럽게 보간하도록하십시오. 기본적으로 목표 값은 0이므로 시뮬레이션이 냉각됩니다. 그러나이 값을 으로 설정하면 드래그 상호 작용 중일 때와 같이 0이 아닌 값으로 설정됩니다 , 당신은 또한 시뮬레이션 열을 가지고 그것을 사용할 수 있습니다. " – ibgib

관련 문제