2016-04-18 8 views
5

Я пытаюсь предварительно вычислить позиции стабильного силового ориентированного графа с использованием igraph и передать их в мой график d3.js. Это связано с размером набора данных, который я буду использовать, что означает, что я не могу полагаться на клиента, чтобы он не замерзал, если вычисление полной силы выполняется на стороне клиента. У меня есть позиции в формате JSON и используются линейные шкалы, чтобы сделать их полезными в d3.js.Предварительно расчитайте и задайте начальные позиции узлов в 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]); 

И так я пытался это сделать. Я экспериментировал с px и py, но результаты те же. Это как если бы этот код никогда не запускался. Если я ввожу console.log, где это видно ниже, значение не печатается. Это независимо от того, где я помещаю этот код, будь то до или после запуска силы.

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

Почему начальное событие не задает начальные позиции моих узлов? Кажется, что они были инициализированы случайным образом. Альтернативно, что является хорошим способом предварительного вычисления стабильного состояния направленного графика силы d3.js? Я взглянул на это на Phantomjs, но сдался.

Спасибо, что нашли время, чтобы прочитать мой вопрос!

EDIT

Вот упрощенный вниз пример: https://jsfiddle.net/xp0zgqes/ Если запустить его несколько раз и обратить внимание на исходных положения узлов вы можете видеть, что они случайно отформатированы.

+0

вы можете предоставить рабочую скрипку с тем, что у вас есть? – iulian

+0

См. Пересмотренный вопрос. –

+0

Действительно, никто? Мне любопытно ... –

ответ

4

Действительно не нравится отвечать на мой собственный вопрос, но я думаю, что это будет действительно полезно. Во-первых, (это может быть специфично только в моем случае), если данные исходной позиции поступают из другого объекта данных, чем данные узла/ссылки, это избавляет вас от необходимости привязывать к двум источникам данных, если вы просто объедините их (или можете умнее меня и просто создайте оригинальный объект json с положениями x и y). В моем случае:

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; 
       } 

Благодаря магии JSON это то, что легко добавлять новые атрибуты к данным, которые хорошо, например, если вы хотите, чтобы ваши узлы были исправлены.

Проблема, похоже, связана с вызовом force.start(). Если вызывается при инициализации такой силы:

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

макет будет случайным образом инициализировать узлы по умолчанию. То, как я обнаружил, что это происходит, заключается в добавлении события на галочке и начале действия позже.

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

И Voilà! Теперь у нас есть полностью функциональный ориентированный по силе график с начальными позициями, установленными из json.

Работа скрипка: https://jsfiddle.net/zbxbzmen/