2013-05-31 12 views
14

Mam diagram sieciowy (wykres ukierunkowany na siłę), wykres rozrzutu i tabelę, które są ze sobą połączone (patrz jsFiddle). Połączenia międzysieciowe działają tak, jak chcę, aby były widoczne po najechaniu myszką. Chciałbym zmodyfikować mój kod tak, aby po najechaniu myszką na węzeł na diagramie sieciowym podświetlony był nie tylko węzeł moused-over (i jego połączenia na wykresie rozrzutu i tabeli), ale także jego sąsiednie węzły są również podświetlone (jak również jako ich połączenia w scatterplot i table).Zastosuj kilka zdarzeń mouseover do sąsiednich (połączonych) węzłów.

Spojrzałem na informacje w Highlight selected node, its links, and its children in a D3 force directed graph o pomoc. Gdzieś po drodze (nie do końca pewny gdzie) znalazłem przykład funkcji, która pomaga zdefiniować podłączone węzły, isConnected().

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

Chciałbym włączyć tę funkcję do moich imprez mouseover, być może za pomocą instrukcji if(), tak, że mogę zrobić wszystko z „podkreślając” że chcę. Ale jestem nowy w D3 i js i nie jestem pewien, jak to skonfigurować.

Poniżej znajduje się fragment kodu (z jsFiddle), które chciałbym zmienić. Byłbym wdzięczny za wszelkie sugestie lub wskazówki do innych przykładów.

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

Odpowiedz

5

W innym scenariuszu Kładę wizualnych obiektów w strukturze danych wykresu i nawigować, że aby skutecznie aktualizować odpowiednie elementy. Ale to jest d3, ale zrobimy to samo, ale zamiast tworzonej przez nas struktury wykresów użyjemy selekcji d3 (które mogą być jak wykresy, ale do tego będą wyglądały bardziej jak tablice). Algorytmicznie takie podejście nie będzie tak skuteczne, ale nasze wykresy są niewielkie.

Tak więc pracując wstecz, będę potrzebował wyboru, który zawiera tylko węzły pobrane sąsiedniego węzła . Zrobię to, wybierając wszystkie kręgi, a następnie używając metody filtru wyboru d3, aby zmniejszyć ją tylko do tych kręgów, które są sąsiadami.

Oczywiście wtedy muszę listę sąsiadów, ale kilka fajnych js metody array zrobić krótką pracę tego. Ostateczna odpowiedni kod (w najechaniu myszą) nie jest jeszcze tak długo - ale dodałem kilka uwag:

// 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'); 

Można również spróbować fiddle

Myślę, że ważnym pojęciem jest tu istotne d3 że gdy kojarzysz dane z elementem (zwykle przy użyciu metod data() lub datum() przy selekcji), to te dane pozostają przy tym elemencie i wszelkie przyszłe selekcje będą zawsze z niego korzystać.

Aby połączyć inne aspekty można wyciągnąć te atrybuty w podobny sposób i połączyć je poprzez D3.Na przykład dla prostokątów lokalizacji, które można dodać do przesunięcia kursora myszy:

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

Jest to pomocne, ale dotyczy tylko podświetlenia sąsiada na diagramie sieci. Chcę również podświetlić odpowiednie bity w tabeli i na mapie. Tak więc, na przykład, gdy kliknę na Grupę A, chcę, aby Jim, Sally i Tom (1) wyróżnili kręgi na diagramie sieciowym (Twój kod adresy to), (2) podświetlone wiersze w tabeli i (3) wyróżnione prostokąty na mapie. Czy możesz mi pomóc z częściami 2 i 3? –

+0

Wygląda jak twoje prostokąty i może twój stół nie kojarzy danych w taki sam sposób jak D3. Ale nie ma powodu, aby i tak nie można było wybrać opcji d3. Sztuką byłoby użycie tablicy indeksów węzła sąsiada, aby uzyskać listę węzłów lub poprawnych atrybutów, aby podświetlić inne elementy. wtedy powinieneś być w stanie zastosować tę samą logikę. – Superboggly

+0

Czy możesz dać mi wskazówkę, jak to zrobić? I próbuje \t \t \t \t 'd3.selectAll ("rect". + D.location) .filter (funkcja (node) { powrotu nodeNeighbors.indexOf (node.index)> 1; }) .style (” stroke "," cyan ");' ale, oczywiście, to nie zadziałało. –

0

To co mi się robi, że zbudowany z funkcją Ego sieci:

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

Dodaj .Na ("mouseover", findEgo) do węzłów oraz następujące powinny działać tak długo, ponieważ masz pewien rodzaj identyfikującego atrybutu uid, który możesz wygenerować po załadowaniu węzłów, jeśli nie jest on przydatny. Jest to trochę przesada, ponieważ pozwala na n stopni sieci ego i tworzy zespolonego stolik dla innych funkcji analizy sieci, ale podstawowa funkcjonalność da ci to, czego chcesz, a może ty lub inni użytkownicy uważają, że aspekt przydatne:

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]; 
} 
} 
Powiązane problemy