2016-04-18 13 views
5

Próbuję wstępnie obliczyć pozycje wykresu ukierunkowanego na siłę, używając igraph i przekazać je do mojego wykresu d3.js. Wynika to z wielkości zbioru danych, który będę używał, co oznacza, że ​​nie mogę polegać na tym, że klient nie zamarza, jeśli pełne obliczenie siły odbywa się po stronie klienta. Mam pozycje w formacie JSON i użyłem liniowych skal, aby były przydatne w d3.js.Wstępne obliczenie i ustawienie początkowych pozycji węzłów w D3.js

var positions = 
{"positions": [{"x":"-68.824367374", "y": "-6.10824525755"}, 
{"x":"-80.8080803911", "y": "-3.38997541264"}, 
{"x":"6.75334817585", "y": "-49.6040729697"}, 
{"x":"14.6608797291", "y": "-81.8897019921"}, 
.... 
var force = d3.layout.force() 
       .charge(-100) 
       .linkDistance(3) 
       .size([width, height]) 
       .nodes(data.nodes) 
       .links(data.links) 
       .start(); 

var posX = d3.scale.linear() 
       .range([0,960]) 
       .domain([-125,120]); 

var posY = d3.scale.linear() 
       .range([0,500]) 
       .domain([-125,125]); 

I w ten sposób próbowałem to zrobić. Eksperymentowałem z px i py, ale wyniki są takie same. To tak, jakby ten kod nigdy nie był uruchamiany. Jeśli wrzucę console.log, gdzie widać poniżej, wartość nie zostanie wydrukowana. Jest to niezależne od tego, gdzie umieściłem ten kod, czy to przed, czy po uruchomieniu siły.

force.on("start", function() { 
        node 
        .data(positions.positions) 
        .attr("cx", function(d) { 
          console.log(posX(d.x)); 
          return posX(d.x); 
         }) 
         .attr("cy", function(d) { 
          return posY(d.y); 
         }) 
       }); 

Dlaczego zdarzenie start on nie ustawia początkowych pozycji moich węzłów? Wydaje się, że są inicjowane losowo. Alternatywnie, jaki jest dobry sposób na wstępne obliczenie stabilnego stanu wykresu ukierunkowanego na siłę d3.js? Spróbowałem zrobić to na Phantomjs, ale zrezygnowałem.

Dziękuję za poświęcenie czasu na przeczytanie mojego pytania!

EDIT

Oto dumbed dół przykład: https://jsfiddle.net/xp0zgqes/ Jeśli uruchomienia go kilka razy i zwrócić uwagę na pozycjach wyjściowych węzłów widać są one losowo zainicjowany.

+0

można dostarczyć skrzypce pracy z tym, co masz? – iulian

+0

Zobacz poprawione pytanie. –

+0

Naprawdę, nikt? Jestem trochę ciekawy ... –

Odpowiedz

4

Naprawdę nie lubię odpowiadać na moje własne pytanie, ale myślę, że będzie to naprawdę przydatne. Po pierwsze, (może to być tylko w moim przypadku specyficzne), jeśli dane początkowej pozycji pochodzą z innego obiektu danych niż dane węzła/łącza, to oszczędza konieczność powiązania z dwoma źródłami danych, jeśli je połączysz (lub możesz bądź mądrzejszy ode mnie i po prostu stwórz oryginalny obiekt json z pozycjami x i y). W moim przypadku:

for (var i = 0; i < data.nodes.length; i++){ 
        data.nodes[i].x = posX(positions.positions[i].x); 
        data.nodes[i].y = posY(positions.positions[i].y); 
        data.nodes[i].newAttribute = value; 
       } 

Dzięki magii JSON łatwo jest dodać nowe atrybuty do danych, które są dobre, np. jeśli chcesz, aby twoje węzły zostały naprawione.

Wydaje się, że problem dotyczy połączenia force.start(). Jeśli zostanie wywołany podczas inicjowania siły w następujący sposób:

var force = d3.layout.force() 
       .charge(-100) 
       .linkDistance(3) 
       .size([width, height]) 
       .nodes(data.nodes) 
       .links(data.links) 
       .start(); 

układ domyślnie inicjalizuje węzły. Sposób, w jaki udało mi się to obejść, polega na dodaniu wydarzenia typu "tick" i uruchomieniu siły później.

var force = d3.layout.force() 
        .charge(-100) 
        .linkDistance(3) 
        .size([width, height]) 
        .nodes(data.nodes) 
        .links(data.links) 
        .on("tick", tick); 

        force.start(); //Note, not chained 


//Standard code that goes in the on.tick event 
function tick() { 
    link.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; }); 

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

I Voila! Mamy teraz w pełni funkcjonalny wykres ukierunkowany na siłę z ustawieniem początkowych pozycji z json.

skrzypce robocza: https://jsfiddle.net/zbxbzmen/