2014-11-15 2 views
1

Я пытаюсь нарисовать то, что, на мой взгляд, составляет граф силы в d3, но в одной плоской линии. Я бы хотел примерно 4-5 точек разного размера в зависимости от их величины, равномерно расположенных между ними (не по центру, а расстояние между сторонами кругов должно быть постоянным) и линии, чтобы присоединиться к ним. Таким образом, в формате ASCII, что-то вроде:d3 force layout как линия (координата y остается неизменной)

o---O---o---O 

Я пытался избежать сложных вычислений, чтобы выяснить координаты центра и начало и конец каждой строки, так что казалось, что расположение силы может сделать трюк. К сожалению, когда я собрал это вместе, я не могу заставить его работать очень хорошо. Часто точки в конечном итоге отстает от других точек, так что для графа 4 узла, как выше, он приходит, ища что-то подобное:

O---O 

Есть ли способ, чтобы получить макет силы работать в 1 измерение вместо 2 ? Или я застрял, выполняя все расчеты расстояния между собой? Код я работаю ниже:

var width = 500; 
var height = 200; 
var svg = d3.select($el[0]) 
    .append('svg') 
    .attr('width', width) 
    .attr('height', height); 

var data_nodes = [ 
    { x: width/2, y: height/2, count: 5 }, 
    { x: width/2, y: height/2, count: 0 }, 
    { x: width/2, y: height/2, count: 1 }, 
    { x: width/2, y: height/2, count: 10 }, 
]; 

var data_links = [ 
    { source: 0, target: 1 }, 
    { source: 1, target: 2 }, 
    { source: 2, target: 3 }, 
]; 

var force = d3.layout.force() 
    .nodes(data_nodes) 
    .links(data_links) 
    .linkDistance(150) 
    .linkStrength(0.5) 
    .gravity(0.7) 
    .friction(0.3) 
    .size([width, height]) 
    .charge(-300); 

var links = svg.selectAll('line') 
    .data(data_links) 
    .enter() 
    .append('line') 
    .attr('stroke', '#65759E') 
    .attr('stroke-width', 4) 
    .attr('x1', function (d) { return data_nodes[d.source].x; }) 
    .attr('y1', function (d) { return data_nodes[d.source].y; }) 
    .attr('x2', function (d) { return data_nodes[d.target].x; }) 
    .attr('y2', function (d) { return data_nodes[d.target].y; }); 

var nodes = svg.selectAll('circle') 
    .data(data_nodes) 
    .enter() 
    .append('circle') 
    .attr('fill', '#65759E') 
    .attr('r', function (d) { return 10 + Math.sqrt(d.count) * 4; }) 
    .attr('cx', function (d, i) { return d.x + i * 10; }) 
    .attr('cy', function (d, i) { return d.y; }); 

force.on('tick', function() { 
    nodes.attr('cx', function (d) { return d.x; }); 
    links.attr('x1', function (d) { return d.source.x; }) 
    .attr('x2', function (d) { return d.target.x; }); 
}); 

force.start(); 
+1

Возможно, было бы намного легче создать этот макет с нуля, чем попытаться сдержать 2D-силовую структуру, чтобы создать приятный 1D-макет. Однако, если вы действительно этого хотите, способ избежать «захвата» в перекрывающиеся круги должен состоять в том, чтобы инициализировать график узлами, упорядоченными в строке в соответствии с порядком их соединений. – AmeliaBR

+0

просто сбросьте координату y в обработчике 'tick' –

+0

@AmeliaBR, который, похоже, сделал трюк. Если вы хотите опубликовать его в качестве ответа, я буду отмечать его как правильное. Я начал сам создавать макет, но вычисления, которые мне пришлось бы сделать, были немного болезненными. – lobati

ответ

0

трудности вы испытываете проистекает из того факта, что не существует никакого способа для узлов, чтобы обойти друг друга, не выходя из линии 1D вы заставляете их в. Отталкивающие силы препятствуют тому, чтобы узел проходил поверх другого узла, чтобы добраться до другой стороны, поэтому они оказались в ловушке этих субоптимальных аранжировок.

По умолчанию d3 force layout инициализирует узлы в случайном положении. Однако вы можете инициализировать их самостоятельно, установив свойства объектов объектов данных перед началом макета и y. Если вы инициализируете график узлами, упорядоченными в строке, в соответствии с порядком их соединений, то макет силы может обрабатывать интервал для вас.

Смежные вопросы