2016-08-16 135 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