我有一个力导向图,想要在点击线条时更改2个节点之间的线条颜色。但是,以下代码会更改所有行的颜色,而不仅仅是我单击的行。
我对该行和点击的行的css是:
.link {
fill: none;
stroke: #666;
stroke-width: 2px;
cursor: pointer;
}
.link--clicked {
fill: none;
stroke: red;
stroke-width: 2px;
cursor: pointer;
}
使用以下方法点击该行时调用函数:
var path = svg.append("g").selectAll("path")
.data(force.links())
.enter().append("path")
.attr("class", function(d) { return "link " + d.type; })
.attr("marker-end", function(d) { return "url(#" + d.type + ")"; })
.on("click", function(d) { edge_clicked(d); });
function edge_clicked(d) {
d3.select("path").classed("link--clicked", false); //remove color class of any previously clicked link
var clicked = d3.select(this); //select clicked element
path.classed("link--clicked", true); //set class of clicked link
}
我怀疑它与我如何调用path.classed命令有关,该命令会影响所有路径/行而不仅仅是单击的行。但是,我无法弄清楚所选行的语法。
感谢任何帮助。
答案 0 :(得分:2)
Gerardo Furtado在answer中已经解决了主要缺点,即范围问题和缺乏使用selectAll
。虽然Gerardo的答案是正确的,但我认为采取不同的方法可能会清理代码和思想。
没有必要使用匿名函数作为click事件的处理程序,除了调用另一个函数之外什么也不做。直接传递函数edge_clicked
作为事件处理程序将解决范围问题。
var path = svg.append("g").selectAll("path")
.data(force.links())
.enter().append("path")
.attr("class", function(d) { return "link " + d.type; })
.attr("marker-end", function(d) { return "url(#" + d.type + ")"; })
.on("click", edge_clicked); // Just pass in the handler function
在这种情况下,处理程序函数this
将引用单击的元素。就个人而言,我也会为这个功能选择一个不同的实现,它看起来更干净,运行速度稍快,因为只需要一个选择而不是两个:
function edge_clicked() {
var clicked = this; // Remember the element clicked upon
d3.selectAll("path").classed("link--clicked", function() {
return clicked === this; // Assign class for clicked element, else unassign class
});
}
这将使用闭包在this
中保存clicked
的值,即点击的元素,以使其在.classed()
的回调中可用。然后,它选择并迭代所有path
,仅将类分配给clicked
元素,同时为任何其他元素取消分配。
答案 1 :(得分:1)
代码中的主要问题是使用this
。在函数edge_clicked内,this
指向window,而不是点击的元素。
要解决这个问题,首先我们将点击的元素传递给函数edge_clicked:
var path = svg.append("g").selectAll("path")
.data(force.links())
.enter().append("path")
.attr("class", function(d) { return "link " + d.type; })
.attr("marker-end", function(d) { return "url(#" + d.type + ")"; })
.on("click", function(d) { edge_clicked(this);});
因此,我们在函数edge_clicked中不再需要this
。
现在我们更改功能:
function edge_clicked(elem) {
d3.selectAll(".link").classed("link--clicked", false);//selectAll instead of select
var clicked = d3.select(elem);
clicked.classed("link--clicked", true);//set class of clicked link
}
请注意,我们首先选择所有(不是select
)链接,然后我们只选择点击的链接。