2016-08-16 84 views
1

我有一个强制导向的图形,当我点击线条时想改变2个节点之间的一条线的颜色。但是,以下代码会更改所有行的颜色,而不仅仅是我单击的那一行。d3 javascript点击一行来改变线条颜色 - 改变所有线条

我对线路和点击在线CSS是:

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 
} 

我怀疑它与我是怎么做的:

.link { 
    fill: none; 
    stroke: #666; 
    stroke-width: 2px; 
    cursor: pointer; 
} 

.link--clicked { 
    fill: none; 
    stroke: red; 
    stroke-width: 2px; 
    cursor: pointer; 
} 

我上线点击使用时调用一个函数调用path.classed命令会影响所有路径/行,而不仅仅是点击行。但是,我无法弄清所选行的语法。

任何帮助表示赞赏。

回答

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);}); 

所以,我们不需要再this的edge_clicked函数内部。

现在我们改变功能:

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)链接,然后我们只选择了一个点击。

+1

谢谢。工作完美。我很欣赏关于范围和selectAll的详细信息。 – JeffA

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元素,而为其他元素取消指定该类。

+0

谢谢你的深思熟虑的答案。我检查了Gerardo Furtado,因为他首先回应并解决了我的方法(范围和selectAll)的主要问题。 – JeffA

+0

@JeffA我很好。这是你的问题,你可以自由接受任何最能帮助你的答案。 Gerardo在指出错误方面做得很好,他提出了一个完美的解决方案。我自己的回答更多地表明了如何通过简化代码来避免这些陷阱。 – altocumulus