2013-05-31 35 views
14

Tôi có biểu đồ mạng (đồ thị theo hướng lực), một phân tán và một bảng được kết nối với nhau (xem jsFiddle). Tôi có các liên kết hoạt động theo cách tôi muốn chúng cho các sự kiện di chuột qua. Tôi muốn sửa đổi mã của mình để khi di chuột qua một nút trong sơ đồ mạng, không chỉ là nút được kết hợp được đánh dấu (và các kết nối của nó trong phân tán và bảng), nhưng các nút lân cận ngay lập tức cũng được đánh dấu (như kết nối của họ trong phân tán và bảng).áp dụng một số sự kiện di chuột đến các nút lân cận (kết nối)

Tôi đã xem thông tin trong số Highlight selected node, its links, and its children in a D3 force directed graph để được trợ giúp. Một nơi nào đó trên đường đi (không chính xác chắc chắn nơi) Tôi tìm thấy một ví dụ về một chức năng giúp xác định các nút kết nối, isConnected().

function isConnected(a, b) { 
    return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index; 
    } 

Tôi muốn kết hợp chức năng này vào các sự kiện mouseover của tôi, có lẽ với một tuyên bố if(), vì vậy mà tôi có thể làm tất cả các "nổi bật" mà tôi muốn. Nhưng, tôi mới đến D3 và js và không chắc chắn làm thế nào để thiết lập nó.

Dưới đây là đoạn mã (từ số jsFiddle) mà tôi muốn sửa đổi. Tôi sẽ đánh giá cao bất kỳ gợi ý hoặc gợi ý cho các ví dụ khác.

var node = svg.selectAll(".node") 
    .data(graph.nodes) 
    .enter().append("g") 
    .attr("class", function(d) { return "node " + d.name + " " + d.location; }) 
    .call(force.drag) 
    .on("mouseover", function(d) { 
     // I would like to insert an if statement to do all of these things to the connected nodes 
     // if(isConnected(d, o)) { 
      d3.select(this).select("circle").style("stroke-width", 6); 
      d3.select(this).select("circle").style("stroke", "orange"); 
      d3.select(this).select("text").style("font", "20px sans-serif"); 
      d3.selectAll("rect." + d.location).style("stroke-width", 6); 
      d3.selectAll("rect." + d.location).style("stroke", "orange"); 
      d3.selectAll("text." + d.location).style("font", "20px sans-serif"); 
      d3.selectAll("tr." + d.name).style("background-color", "orange"); 
      //} 
     }) 
    .on("mouseout", function(d) { 
     // if(isConnected(d, o)) { 
      d3.select(this).select("circle").style("stroke-width", 1.5); 
      d3.select(this).select("circle").style("stroke", "gray"); 
      d3.select(this).select("text").style("font", "12px sans-serif"); 
      d3.selectAll("rect." + d.location).style("stroke-width", 1.5); 
      d3.selectAll("rect." + d.location).style("stroke", "gray"); 
      d3.selectAll("text." + d.location).style("font", "12px sans-serif"); 
      d3.selectAll("tr." + d.name).style("background-color", "white"); 
      //} 
     }); 

Trả lời

5

Trong một trường hợp khác, tôi sẽ đặt đối tượng trực quan của mình vào cấu trúc dữ liệu biểu đồ và điều hướng để cập nhật hiệu quả các mục thích hợp. Nhưng đây là d3, nhưng vì vậy chúng ta sẽ làm điều tương tự nhưng thay vì cấu trúc dữ liệu đồ thị mà chúng ta tạo ra, chúng ta sẽ sử dụng các lựa chọn d3 (có thể giống như đồ thị nhưng đối với chúng sẽ trông giống nhiều mảng hơn). Về mặt thuật toán, cách tiếp cận này sẽ không hiệu quả, nhưng đồ thị của chúng ta nhỏ.

Vì vậy, làm việc về phía sau tôi sẽ muốn một lựa chọn chỉ bao gồm các nút lân cận của nút được chọn . Tôi sẽ làm điều này bằng cách chọn tất cả các vòng tròn và sau đó sử dụng phương pháp lọc lựa chọn d3 để giảm chỉ cho những vòng tròn đó là hàng xóm.

Tất nhiên sau đó tôi cần danh sách hàng xóm, nhưng một vài phương pháp mảng js đẹp làm cho công việc ngắn về điều đó. Mã liên quan cuối cùng (trong mouseover) không phải là thậm chí là lâu - nhưng tôi đã thêm một loạt các bình luận:

// Figure out the neighboring node id's with brute strength because the graph is small 
var nodeNeighbors = graph.links.filter(function(link) { 
    // Filter the list of links to only those links that have our target 
    // node as a source or target 
    return link.source.index === d.index || link.target.index === d.index;}) 
.map(function(link) { 
    // Map the list of links to a simple array of the neighboring indices - this is 
    // technically not required but makes the code below simpler because we can use   
    // indexOf instead of iterating and searching ourselves. 
    return link.source.index === d.index ? link.target.index : link.source.index; }); 

// Reset all circles - we will do this in mouseout also 
svg.selectAll('circle').style('stroke', 'gray'); 

// now we select the neighboring circles and apply whatever style we want. 
// Note that we could also filter a selection of links in this way if we want to 
// Highlight those as well 
svg.selectAll('circle').filter(function(node) { 
    // I filter the selection of all circles to only those that hold a node with an 
    // index in my listg of neighbors 
    return nodeNeighbors.indexOf(node.index) > -1; 
}) 
.style('stroke', 'orange'); 

Bạn cũng có thể thử các fiddle

Tôi nghĩ rằng khái niệm d3 quan trọng liên quan ở đây là khi bạn kết hợp dữ liệu với một phần tử (thường sử dụng các phương thức data() hoặc datum() trên các lựa chọn) thì dữ liệu đó sẽ dính với phần tử đó và mọi lựa chọn trong tương lai sẽ luôn sử dụng nó.

Để liên kết các khía cạnh khác, bạn có thể kéo các thuộc tính đó theo cách tương tự và liên kết chúng thông qua d3.Ví dụ: đối với hình chữ nhật vị trí bạn có thể thêm để di chuột qua:

var nodeLocations = graph.links.filter(function(link) { 
     return link.source.index === d.index || link.target.index === d.index;}) 
    .map(function(link) { 
     return link.source.index === d.index ? link.target.location : link.source.location; }); 

d3.selectAll("rect").filter(function(node) { return nodeLocations.indexOf(node.location) > -1; }) .style("stroke", "cyan"); 
+0

Điều này hữu ích, nhưng nó chỉ áp dụng hàng xóm làm nổi bật sơ đồ mạng. Tôi cũng muốn làm nổi bật các bit tương ứng trong bảng và bản đồ. Vì vậy, ví dụ, khi tôi di chuyển GroupA, tôi muốn Jim, Sally và Tom có ​​(1) vòng tròn được đánh dấu trong sơ đồ mạng (mã của bạn địa chỉ này), (2) các hàng được tô sáng trong bảng và (3) được tô sáng hình chữ nhật trong bản đồ. Bạn có thể giúp tôi với các bộ phận 2 và 3 không? –

+0

Dường như hình chữ nhật của bạn và có thể bảng của bạn không liên kết dữ liệu giống như D3. Nhưng không có lý do bạn không thể sử dụng d3 lựa chọn anyway. Bí quyết sẽ là sử dụng mảng các chỉ mục nút lân cận để thực sự có được danh sách các nút hoặc thuộc tính chính xác để làm nổi bật các mục khác. thì bạn sẽ có thể áp dụng cùng một logic. – Superboggly

+0

Bạn có thể cho tôi gợi ý về cách thực hiện việc này không? Tôi cố gắng \t \t \t \t 'd3.selectAll ("rect." + D.location) .filter (function (node) { trở nodeNeighbors.indexOf (node.index)> -1; }) .style (" đột quỵ "," cyan ");" nhưng, rõ ràng, điều đó không hiệu quả. –

0

điều này tôi đã xây dựng nào đó với tính năng Ego Mạng:

https://gist.github.com/emeeks/4588962

Thêm một .Trên ("mouseover", findEgo) để nút của bạn và sau đây nên làm việc, miễn vì bạn có một số loại xác định thuộc tính uid, mà bạn có thể tạo ra khi bạn tải các nút nếu một nút không thuận tiện. Đó là một chút quá mức cần thiết, vì nó cho phép mạng bản ngã n độ và tạo bảng tổng hợp cho các chức năng phân tích mạng khác, nhưng chức năng cơ bản sẽ cung cấp cho bạn những gì bạn muốn và bạn hoặc người dùng khác có thể thấy khía cạnh đó hữu ích:

function findEgo(d) { 
    var computedEgoArray = findEgoNetwork(d.id, 1, false,"individual"); 
    d3.selectAll("circle.node").style("fill", function(p) {return p.id == d.id ? "purple" : computedEgoArray.indexOf(p.id) > -1 ? "blue" : "pink"}) 
} 

function findEgoNetwork(searchNode, egoNetworkDegree, isDirected, searchType) { 
    var egoNetwork = {}; 
    for (x in nodes) { 
    if (nodes[x].id == searchNode || searchType == "aggregate") { 
    egoNetwork[nodes[x].id] = [nodes[x].id]; 
    var z = 0; 
    while (z < egoNetworkDegree) { 
    var thisEgoRing = egoNetwork[nodes[x].id].slice(0); 
    for (y in links) { 
    if (thisEgoRing.indexOf(links[y].source.id) > -1 && thisEgoRing.indexOf(links[y].target.id) == -1) { 
    egoNetwork[nodes[x].id].push(links[y].target.id) 
    } 
    else if (isDirected == false && thisEgoRing.indexOf(links[y].source.id) == -1 && thisEgoRing.indexOf(links[y].target.id) > -1) { 
    egoNetwork[nodes[x].id].push(links[y].source.id) 
    } 
} 
z++; 
} 
} 
} 
if (searchType == "aggregate") { 
//if it's checking the entire network, pass back the entire object of arrays 
return egoNetwork; 
} 
else { 
//Otherwise only give back the array that corresponds with the search node 
return egoNetwork[searchNode]; 
} 
} 
Các vấn đề liên quan