Я пытаюсь построить диаграмму направленной силы в d3.js, на которой есть прослушиватель кликов, который изменяет базовые данные и перерисовывает граф. Я верю, что следую шаблону обновления г-на Бостока, но проблема, с которой я столкнулась, заключается в том, что когда я запускаю обновление, инициированное клиентом, узлы исчезают в нижней части экрана, оставляя ссылки и метки позади.force graph in d3.js - исчезающие узлы
Это обновление, похоже, запускается, обновляет существующие узлы (в этом случае их зеленым), а затем игнорирует разделы «ввод» и «выход» (что является желаемым поведением), а затем обращается к функции tick(), которая отправляет узлы юга.
Я могу заставить это работать, удалив тег «g» на узле и тем самым развязывая метки и узел, что явно нежелательно.
Я не могу не чувствовать, что мне не хватает чего-то очевидного! Или, может быть, я должен придерживаться этого по-другому?
Вот код:
var width = 960,
height = 500,
links,
nodes,
root;
var force = d3.layout.force()
.size([width, height])
.charge(-200)
.linkDistance(50)
.on("tick", tick);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var link = svg.selectAll(".link"),
node = svg.selectAll(".node");
d3.json("test.json", function(json) {
root = json;
update();
});
function update() {
nodes = root.nodes
links = root.links
// Restart the force layout.
force
.nodes(nodes)
.links(links)
.start();
svg.append("svg:defs").append("marker")
.attr("id", "end")
.attr("refX", 15)
.attr("refY", 2)
.attr("markerWidth", 6)
.attr("markerHeight", 4)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M 0,0 V 4 L8,2 Z");
// Update the links…
//link = link.data(links, function(d) { return d.target.name; });
link = link.data(links)
// Exit any old links.
link.exit().remove();
// Enter any new links.
link.enter().insert("svg:line", ".node")
.attr("class", "link")
.attr("marker-end", "url(#end)")
.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; });
// Update the nodes…
node = svg.selectAll("g").select(".node").data(nodes, function(d) { return d.name; });
node.style("fill", "green")
// Exit any old nodes.
node.exit().remove();
// Enter any new nodes.
node.enter().append("g")
.append("svg:circle")
.attr("class", "node")
.attr("id", function(d) {return "node" + d.index; })
.attr("r", 12)
.style("fill", "#BBB")
.on("click", click)
.call(force.drag);
node.append("svg:text")
.attr("dx", 16)
.attr("dy", ".15em")
.attr("class", "nodelabel")
.text(function(d) { return d.name });
}
function tick() {
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 + ")"; });
}
function click(d) {
if (!d3.event.defaultPrevented) {
// DO ANYTHING
update()
}
}
и содержание test.json является:
{
"nodes": [
{"name" : "John"},
{"name" : "Alison"},
{"name" : "Phil"},
{"name" : "Jim"},
{"name" : "Jane"},
{"name" : "Mary"},
{"name" : "Joe"}
],
"links": [
{"source": 1, "target": 0},
{"source": 2, "target": 0},
{"source": 3, "target": 0},
{"source": 4, "target": 0},
{"source": 5, "target": 1},
{"source": 6, "target": 1}
]
}
Силовой макет не позволяет сбросить узлы и ссылки. Чтобы изменить их, установите их один раз, а затем измените основные структуры данных. Не вызывайте 'force.nodes()' или 'force.links()' несколько раз. –
Полезно знать, спасибо. Однако, если я перемещаю этот кусок вне функции update(), у меня все еще есть та же проблема. – alexmloveless
Вы также должны сделать выбор снова внутри 'update()' - ваша переменная 'link' содержит результат выполнения выбора. –