2012-11-30 35 views
5

Moim celem jest użycie układu sił d3 do wyświetlania dwóch różnych sieci, które dzielą te same węzły. Na przykład wśród czterech osób możesz zdefiniować sieć społecznościową i sieć genealogiczną; węzły będą takie same (ludzie), ale powiązania (relacje) mogą być różne. Pomimo utworzenia dwóch oddzielnych układów sił, dwóch oddzielnych płótn svg i próby zdefiniowania oddzielnych zmiennych, węzły dzielą się informacjami pozycyjnymi x i y. Oto minimalny przykład, w którym przeciągając węzły w jednej sieci zmienia swoje stanowiska w innej sieci: http://amath.colorado.edu/student/larremore/nodesSharingPositiond3Wiele instancji układu sił d3 na tej samej stronie

Poniżej napisałem funkcję, która nazywa się stworzyć jedną z sieci, a kod, aby stworzyć inne są bardzo podobne, ale używają różnych nazw zmiennych we wszystkich przypadkach. Skomentowany kod do tworzenia obu sieci można znaleźć w http://amath.colorado.edu/student/larremore/nodesSharingPositiond3/lib/minimal.js, a skrypt używany do definiowania zmiennych można znaleźć w /driver/minimalScript.js < - Nie mam wystarczającej reputacji, aby połączyć to bezpośrednio. Przepraszam!

Gdzieś w sposobie działania d3.force informacje o położeniu są globalne lub są wybierane globalnie lub coś. Czy ktokolwiek mógłby rzucić na to światło? Interesuje mnie zarówno rozwiązanie polegające na oddzieleniu informacji o położeniu, jak i zrozumienie, w jaki sposób d3.force obsługuje i aktualizuje obliczenia pozycji.

function makeYNet() { 

// This populates the YactiveLinks variable with the proper YLinks. The goal is to be able to only display links whose value is above some threshold. 
for (var i=0; i<YLinks.length; i++) { 
    if (YLinks[i].link2 > thr) { 
     YactiveLinks.push(YLinks[i]); 
    } 
} 

// Add nodes and links to forceY 
forceY 
.nodes(YNodes) 
.links(YactiveLinks); 

// Draw lines 
var Ylink = svgY.selectAll("line.link") 
.data(YactiveLinks) 
.enter() 
.append("line") 
.attr("class", "link") 
.style("stroke-width", 2.0); 

// Draw nodes 
var Ynode = svgY.selectAll("circle.node") 
.data(YNodes) 
.enter().append("circle") 
.attr("class", "node") 
.attr("r", radius) 
.attr("high",0) 
.attr("id", function(d,i) { 
     return ("idy" + i); 
     }) 
.style("fill", function(d) { return color(d.group1); }) 
.call(forceY.drag) 
; 

// Define tick 
forceY.on("tick", function() { 
      Ylink 
      .attr("x1", function(d) { return d.source.x; }) 
      .attr("y1", function(d) { return d.source.y; }) 
      .attr("x2", function(d) { return d.target.x; }) 
      .attr("y2", function(d) { return d.target.y; }); 

      Ynode.attr("cx", function(d) { return d.x; }) 
      .attr("cy", function(d) { return d.y; }); 
      }); 

// Start 'er up 
forceY.start(); 
} 
+0

Próbuję zrobić to samo, co ty: zsynchronizuj pozycje węzłów dwóch układów sił na tej samej stronie. Mam dwa układy siłowe, które działają dzięki odpowiedzi Alexa Reynoldsa. Jednak nie wiem, gdzie ustawić haczyki do synchronizacji pozycji.Ponieważ linki do podejścia DBLaremore już nie działają, czy ktoś może wskazać, od czego zacząć, a może linki do innego przykładu? – tty56

Odpowiedz

4

pisałem narzędzie, które umożliwia przeglądanie biologiczną regulatory networks, pokazując dwa panele SVG side-by-side. Każdy panel zawiera sieć z wymuszonym układem, zgodnie z rysunkiem interfejsu API d3.js.

Stwierdziłem, że kluczem do wykonania tej pracy jest nadanie każdemu elementowi DOM niepowtarzalnej nazwy, w której może występować duplikacja.

W moim przypadku użyłem _left i _right jako wystarczającej dla każdego elementu panelu, w którym element znajduje się odpowiednio w lewym lub prawym panelu. Trzeba dużo pracy, aby śledzić, ale renderer sieci może kierować swoje połączenia i zdarzenia do właściwego elementu i sieci.

W twoim przypadku:

.attr("id", function(d,i) { 
     return ("idx" + i); 
     }) 

Chcesz zastąpić wartość return z czymś, co jednoznacznie określa sieć, że węzeł jest skojarzony. Niezależnie od tego, czy używasz schematu numerowania indeksu, czy podejścia opartego na sufiksie, tak jak ja, problemem jest upewnienie się, że wszystkie nazwy id są unikalne.

+0

Przykład witryny jest dobry do naśladowania - wygląda świetnie! Nie mogę jednak rozwiązać problemu, zmieniając identyfikatory. Próbowałem używać różnych identyfikatorów, jak również żadnych identyfikatorów iw obu przypadkach wyświetlacze ciągle się aktualizują. Sprawdziłem, czy nazwy dla lewej (X) i prawej (Y) różnią się nazwami układu, węzłów, łączy i kanw svg. Jakieś inne sugestie? Nie wiem, czy jest to istotne, ale jeśli przeciągniesz i przytrzymasz jedną sieć wystarczająco długo, druga ostygnie/zamrozi i nie będzie już połączona (podobno). – DBLarremore

+0

Nie wiem, co jeszcze by działało. Wiem, że upewnienie się, że każdy element w każdej sieci jest unikalny, jest kluczem do tego. Jeśli istnieją zduplikowane nazwy "id", rzeczy się psują. Chciałbym móc pomóc! –

+0

Kolejne rzeczy, które zauważyłem (być może) stanowią wskazówkę: Po pewnym czasie/rozproszeniu, układ zamrozi węzły w ich bieżącej lokalizacji. Jeśli złapiesz lewy układ i przesuniesz go, aż prawo zamrozi się, nie będziesz już mógł pośrednio przesuwać odpowiedniego układu. Następnie, jeśli weźmiesz odpowiedni układ, możesz go użyć, by wpłynąć na lewą ** tylko ** dopóki lewe zawieszenie się nie powiedzie. Według mnie oznacza to, że podczas zmiany położenia układu, ruch nie wpływa na czas chłodzenia. Węzły poruszają się na obu polach, ale tylko jedna rejestruje dynamikę. – DBLarremore

0

Javascript jest znany z ukrywania, czy stan jest udostępniony czy nie. Twój minimalny przykład nie jest już dostępny, ale kiedy napotkałem ten sam problem, mój wniosek był taki, że robiłem tylko płytkie kopie, gdzie potrzebowałem kompletnych klonów. (Mówię o łączach i węzłach, które D3 bierze jako dane wejściowe).

Bez prawdziwej kopii, wynikowe zachowanie będzie nieco losowe, jak odkryłeś, w zależności od tego, czy kod D3 wybierze modyfikację udostępnionych danych "in situ" lub nie. Ogólnie rzecz biorąc, D3 próbuje , a nie tworzyć kopie ze względu na wydajność.

To jest powód, dla którego obejście obejścia json zadziała: przez całkowite usztywnienie wszystkich danych, de facto wymuszasz operację klonowania.