2016-10-04 2 views
3

Я пытаюсь добавить узлы один за другим к симуляции симуляции d3 (в версии 4!), Но некоторые из них, похоже, не эволюционируют с помощью моделирования после того, как они были созданы ,d3 v4 силы, действующие на динамически добавленные узлы


В настоящее время моделирование назначает один узел, то функция, ADDNODE вызывается дважды добавляя больше двух узлов. Каждый из них добавляется к симуляции, имеет круг и визуализированную линию и добавляет событие курсора один за другим.

(Технически первый и второй узел сделаны в то же время, как первый только установить, когда ADDNODE вызываются на втором)

Затем, когда узел нажат, новый узел, связанный к одному под курсором, должен быть создан. Затем этот узел должен развиваться под силовыми симуляторами, как и любой другой.


Однако в то время как один или два узла, кажется, созданы хорошо, кажется, позже узлы не будут развиваться в рамках моделирования. В частности, многомерная сила, которая должна удерживать некоторое пространство между узлами, не работает.


Моя интуиция, что узлы добавляются в неподходящее время для галочкой функции при моделировании (в более ранние проблемы были решены путем добавления некоторых 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

Силе моделирования, как следует из названия, является моделирование на частицах, взаимодействующих друг с другом. Alpha используется, чтобы помочь свести систему, затухая на каждой итерации. Силы умножаются на альфа, поэтому на каждой итерации силы становятся слабее, пока альфа не достигнет очень низкого значения, когда симуляция прекратится. Из d3 документации:

simulation.restart() <>

Restarts внутренний таймер при моделировании и возвращает моделирование. В сочетании с simulation.alphaTarget или simulation.alph этот метод может использоваться для «повторного нагрева» моделирования во время взаимодействия, такого как , как при перетаскивании узла, или для возобновления моделирования после временного , приостанавливая его с помощью метода моделирования.

Когда вы добавляете узел, симуляция уже остановлена, поэтому вам нужно «повторно разобрать» симуляцию с альфа-1.

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

    simulation.alpha(1); // <---- reheat; 

    restartSim(); 

Вот обновленный код пера: http://codepen.io/anon/pen/amqrWq?editors=0010

+0

Это прекрасно работает, большое спасибо. Есть ли простой способ понять, что здесь делает альфа? «Повторный нагрев» не кажется мне очень интуитивным, а [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)« Это позволяет вам установить «желаемую» альфу для моделирование и моделирование плавно интерполируют в направлении желаемого значения. По умолчанию целевое значение равно нулю, так что имитация охлаждается. Однако, установив его на ненулевое значение, например, во время взаимодействия с перетаскиванием , вы также можете использовать его, чтобы иметь симуляция моделирования ». – ibgib

Смежные вопросы