EDIT: добавлен пример codepen
Я экспериментирую с симуляцией силы D3v4, но в настоящее время я не могу правильно добавить новые узлы в график. Здесь настройка
var svgRef = d3.select("body").append("svg")
.attr("width",svgWidth)
.attr("height",svgHeight)
.on("mousedown",svgClick);
var nodes_data = [{id: "0"},{id: "1"},{id: "2"}];
var links_data = [{source:"1",target:"2"}];
var linksRef = svgRef
.selectAll(".link")
.data(links_data).enter()
.append("line").attr("class", "link");
var nodesRef = svgRef
.append("g").attr("class", "nodes")
.selectAll(".node")
.data(nodes_data).enter()
.append("g").attr("class", "node")
.call(d3.drag()...);
nodesRef.append("circle")
.attr("r", nodeRadius);
Я создаю группу для отдельных узлов, чтобы держать их circle
title
и text
и т.д., И все эти узлы создаются в большей группе "узлы". Конечный результат выглядит следующим образом:
<svg>
...
<g class="nodes">
<g class="node">
<circle>
<text>
...
</g>
<g class="node"></g>
<g class="node"></g>
...
</g>
</svg>
Затем я добавляю новый узел к своим данным и пытаюсь вставить его в график
function svgClick(){
// add new node
nodes_data.push({id: nodeCount++, "x":d3.event.X, "y":d3.event.y});
// restart simulation
simulation.nodes(nodes_data).on("tick", ticked);
// insert new nodes
nodeEnter = svgRef
.selectAll(".node")
.data(nodes_data).enter()
.append("g").attr("class", "node")
.call(d3.drag()...)
.append("circle")
.attr("class", "node")
.attr("r", nodeRadius);
// merge new nodes
nodesRef = nodeEnter.merge(nodesRef);
}
2 вещи, которые идут не так, что я не могу исправить:
вставленный узел не отображается в координатах мыши. Вычислите это, просто опечатку в d3.event.X
где X должен быть нижним.
вставленный узел не добавляется в <g class="nodes">
но ниже. Я не могу найти способ правильно выбрать его
Вот так:
<svg>
<g class="nodes">
<g class="node"></g>
<g class="node"></g>
</g>
<g class="node"></g> // <--- inserted here
</svg>
Для вашей второй проблемы: "вставленный узел не добавлен, но ниже. Я не могу найти способ его правильно выбрать", как вы вводите новые узлы, объясняет, почему вы в конечном итоге со структурой, которую у вас есть:
nodeEnter = svgRef
.selectAll(".node") // select all elements with class node in the svg
.data(nodes_data) // bind new data to them
.enter() // enter new nodes where needed
.append("g") // append a g for each new node needed to the svg
Это добавляет новые узлы прямо к родительскому svg: svgRef.selectAll(...)...
Если мы хотим добавить новые узлы к родительскому, мы должны сначала выбрать этого родителя. Если бы мы хотели использовать g
с nodes
класса в качестве родительского элемента для новых узлов, мы бы использовали: svgRef.select(".nodes").selectAll(...)...
Это будет выглядеть так:
nodeEnter = svgRef
.select(".nodes") // select the parent g with class nodes
.seleactAll(".node") // select all nodes in that parent
.data(nodes_data) // bind new data to them
.enter() // enter new nodes where needed
.append("g") // append a g for each new node needed to the g with class nodes
Кроме того, вы хотите, чтобы nodeEnter был g
элементами, а не элементами circle
, чтобы вы могли разделить цепочку. Кругам также не нужен узел класса, поскольку родительский элемент g имеет его
Для позиционирования вы используете d3.event.X
а не d3.event.x
а в кодефене, в отличие от вопроса, вы используете свойства cx, cy для узла (сила принимает позицию как x, y свойства).
Здесь обновляется ручка.
Имейте в виду, что если тик отключается, новые узлы не располагаются так, как они помещаются на каждом тике, а не на добавлении (сброс альфы, если вы хотите обеспечить тик). Кроме того, вы можете заметить, что демпфирование происходит из-за d3.forceCenter, который стремится обеспечить центр тяжести узлов указанной точки (вы можете применить силу позиционирования вместо d3.forceCenter, если вы хотите избежать этой проблемы)
select(".nodes")
но получаю странный результат, когда узлы не перерисовываются. Нужно ли мне .restart () где-нибудь?
.select(".nodes").selectAll(".nodes")
во второй блок кода ответа - я скопировал первый блок кода и сделал только половину модификация, ручка в ответе должна быть правильной все же все же. Я обновил ответ, чтобы исправить ошибку.