2012-06-14 5 views
3

Я пытаюсь «имитировать» гравитационные силы на частицах, когда они движутся к «фокальной» точке. Практически говоря, я пытаюсь изменить следующий код, чтобы частицы были слегка оттолкнуты оранжевым узлом на пути к синему узлу. Моя проблема в том, что у меня возникли проблемы с концептуализацией этого подхода с использованием макетов D3.js. Я понимаю, что это довольно неопределенный вопрос, но любая помощь очень ценится! Изображение и код ниже:Взаимодействующие силы с D3.js

enter image description here

<!DOCTYPE html> 
<html> 
    <head> 
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> 
    <title>Force Layouts - Quantitative Foci</title> 
    <script type="text/javascript" src="http://d3js.org/d3.v2.min.js?2.8.1"></script> 
    <style type="text/css"> 

circle { 
    stroke: #fff; 
} 

svg { 
    fill: #fff; 
    stroke: #000; 
} 

    </style> 
    </head> 
    <body> 
    <div id="body"> 
     <div id="chart"></div> 
    </div> 
    <script type="text/javascript"> 

var w = 1280, 
    h = 800, 
    color = d3.scale.category10(); 

var force = d3.layout.force() 
    .gravity(0) 
    .charge(-5) 
    .linkStrength(0) 
    .size([w, h]); 

var links = force.links(), 
    nodes = force.nodes(), 
    centers = [ 
     {type: 0, x: 3 * w/6, y: 2 * h/6, fixed: true}, 
     {type: 1, x: 4 * w/6, y: 4 * h/6, fixed: true} 
    ]; 

var svg = d3.select("#chart").append("svg:svg") 
    .attr("width", w) 
    .attr("height", h); 

svg.append("svg:rect") 
    .attr("width", w) 
    .attr("height", h); 

svg.selectAll("circle") 
    .data(centers) 
    .enter().append("svg:circle") 
    .attr("r", 12) 
    .attr("cx", function(d) { return d.x; }) 
    .attr("cy", function(d) { return d.y; }) 
    .style("fill", fill) 
    .call(force.drag); 

force.on("tick", function(e) { 
    var k = e.alpha * .1; 
    nodes.forEach(function(node) { 
    var center = centers[node.type]; 
    node.x += (center.x - node.x) * k; 
    node.y += (center.y - node.y) * k; 
    }); 

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

    svg.selectAll("line") 
     .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; }); 
}); 

var p0; 

svg.on("mousemove", function() { 
    var p1 = d3.svg.mouse(this), 
     a = {type: 0, x: p1[0], y: p1[1], px: (p0 || (p0 = p1))[0], py: p0[1]}, 
     b = {type: 1, x: centers[1].x, y: centers[1].y, fixed:true}, 
     link = {source: a, target: b}; 

    p0 = p1; 

    svg.selectAll() 
     .data([a, b]) 
    .enter().append("svg:circle") 
     .attr("cx", function(d) { return d.x; }) 
     .attr("cy", function(d) { return d.y; }) 
     .attr("r", 4.5) 
     .style("fill", fill) 
    .transition() 
     .delay(3000) 
     .attr("r", 1e-6) 
     .remove(); 

    svg.insert("svg:line", "circle") 
     .data([link]) 
    .transition() 
     .delay(3000) 
     .each("end", function() { 
     nodes.splice(nodes.indexOf(a), 1); 
     nodes.splice(nodes.indexOf(b), 1); 
     links.splice(links.indexOf(link), 1); 
     }) 
     .remove(); 

    nodes.push(a, b); 
    links.push(link); 
    force.start(); 
}); 

function fill(d) { 
    return color(d.type); 
} 

    </script> 
    </body> 
</html> 

1http://jsfiddle.net/fbW7T/1/ - раньше.

[2] http://jsfiddle.net/fbW7T/2/ - после, с предложением Лефикса.

ответ

2

Прежде всего, ваш вопрос очень интересный :).
Заменить force.on («tick», function (e) {...}) со следующими кодами. На самом деле я просто добавляю переменную и 10 строк кода в функцию.
fr означает радиус зоны круга, в котором частицы должны покинуть оранжевый узел.

var fr = 100; 
force.on("tick", function(e) { 
    var k = e.alpha * .1; 
    nodes.forEach(function(node) { 
    var center = centers[node.type]; 
    node.x += (center.x - node.x) * k; 
    node.y += (center.y - node.y) * k; 

if (node.type == 0) { 
    center = centers[1]; 
    while (Math.abs(node.x - center.x) < fr && Math.abs(node.y - center.y) < fr) { 
     if (Math.abs(node.x - center.x) >= Math.abs(node.y - center.y)) { 
      node.x += (node.x - center.x)/Math.abs(node.x - center.x); 
     } else { 
      node.y += (node.y - center.y)/Math.abs(node.y - center.y); 
     } 
    } 
} 
}); 

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

svg.selectAll("line") 
    .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; }); 
}); 
Смежные вопросы