d3 Не правильно отменять выбор узлов
У меня есть эта функция "выбрать узел" в моем графе силы d3. По какой-то причине он ведет себя не так, как должен. Код должен сделать это так, когда пользователь дважды щелкает узел, который он выбирает / отменяет выбор (возвращается к нормальному цвету / становится желтым). Все работает, когда вы выбираете, а затем отменяете выбор узла. Проблема возникает в следующих случаях:
- Если вы выберете узел A, затем выберите узел B (в этот момент они оба желтого цвета, как и должно быть), затем вернитесь назад и дважды щелкните узел A, чтобы отменить выбор, и он снова будет считан выбранным (остается желтым).
- Когда вы выбираете узел A, затем выбираете узел B. Затем вы дважды щелкаете по узлу B, чтобы отменить выбор, он будет работать, как задумано. Но когда вы вернетесь к двойному щелчку по узлу A (который все еще выбран), чтобы отменить выбор, он будет считан как выбранный.
Вот некоторые фрагменты кода, откуда, я думаю, проблема.
var edges = [];
var nodes = [];
var nodesHash = {};
function update() {
// clear stack of selected nodes
selectedNodes = [];
// Update link data based on edges array.
link = link.data(edges);
// Create new links
link.enter().append("line")
.attr("class", "link")
.style("stroke-width", 1.5);
// Delete removed links
link.exit().remove();
// Update node data based on nodes array.
node = node.data(nodes);
// Create new nodes
node.enter().append("g")
.attr("class", "node")
.attr("id", function(d) { return d.data['id'] })
.call(force.drag)
.on('mouseover', connectedNodes)
.on('mouseleave', restore)
.on('dblclick', highlight);
// Delete removed nodes
node.exit().remove();
node.append("circle").attr("r", 11);
node.classed("selected", function(d) { return d === d.selected; })
// Node behavior for checking if selected otherwise colors nodes to color given from JSON.
node.style("fill", function(d) {
if (d.selected === false) {
return d.data['color']
update();
}
else {
return "yellow";
update();
}
}).select("circle").style("stroke", "black");
// Link color based on JSON data.
link.style("stroke", function(d) { return d.data['color'] });
// Adds text to nodes
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.style("fill", "black")
.text(function (d) { return d.data['label']; });
// Creates an index used to figure out neighbor nodes.
root.edges.forEach(function (d) {
linkedByIndex[d.data.source + "," + d.data.target] = 1;
});
// responsive behavior for graph based on window.
window.addEventListener('resize', resize);
force.on("tick", function() {
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 + ")"; });
});
force.start();
}
// Reset Mouse Variables
function resetMouseVars() {
mousedown_node = null;
mouseup_node = null;
mousedown_link = null;
}
// Highlighting of selected node.
function highlight(d) {
mousedown_node = d;
if (mousedown_node != selected_node) {
console.log("Selected: " + mousedown_node.data['id']);
selected_node = mousedown_node;
selected_node.selected = true;
}
else {
console.log("De-Selected: " + mousedown_node.data['id']);
selected_node = mousedown_node;
selected_node.selected = false;
}
resetMouseVars();
update();
}
function spliceLinksForNode(node) {
toSplice = edges.filter(
function(e) {
return (e.source === node) || (e.target === node); });
toSplice.map(
function(e) {
edges.splice(edges.indexOf(e), 1); });
}
// Delete node with prompt
function deleteNode() {
console.log("Prompted to delete: " + selected_node);
if (confirm("Deleting selected elements will remove them from the graph entirely. Are you sure?")) {
if (!selected_node) alert("No node selected");
if (selected_node) {
console.log("Deleted: " + selected_node);
selected_node.removed = true;
nodes.splice(nodes.indexOf(selected_node), 1);
spliceLinksForNode(selected_node);
}
selected_node = null;
update();
}
}
Так что в моем коде node.on('dblclick', highlight)
просто изменяет текущее выбранное свойство узлов, независимо от того, выбрано оно или нет. node.style
выполняет фактическую проверку свойства и меняет цвет.
Будем благодарны за любую помощь в том, почему происходит такое странное поведение!
1 ответ
Если вы выберете A, то selected_node
устанавливается в А.
Затем, если вы выберете B, то selected_node
устанавливается в B
Затем, если вы нажмете еще раз, то внутри highlight()
, выражение mousedown_node != selected_node
оценивает true
потому что, который mousedown_node
не равно selected_node
, который по-прежнему B, из предыдущего выбора.
Так что это ошибка.
Если вы разрешаете множественный выбор, то нет никакой переменной selected_node
достаточно, чтобы захватить состояние выбора. Если бы у вас был selected_nodes
Массив, из которого вы добавляете и удаляете узлы, тогда вы можете проверить selected_nodes.indexOf(mousedown_node) > -1
чтобы определить, если он выбран.
Но на самом деле, я не понимаю, зачем вам вообще нужна вся эта логика - если, возможно, какой-то код, который вы не включили, полагается на selected_node
, На самом деле, все ваши функции выделения должны быть просто
function highlight(d) {
d.selected = !d.selected;
update();
}
И это должно исправить вашу проблему.