2017-07-25 124 views
0

我正嘗試使用d3.js v4創建一個強制佈局,並且市長部分在使用拖動行爲時非常適合接受一個問題。D3.js v4使用鏈接力強制佈局會在使用拖動行爲時導致奇怪的移動

當拖動它周圍的其他節點,它們沒有連接到點擊節點的節點上單擊,飛走:

var svg = d3.select("svg"), 
width = +svg.attr("width"), 
height = +svg.attr("height"); 

function drawNode(nodes) { 
    return svg.selectAll("circle.node") 
     .data(nodes, function (d, i) { return d.Id; }) 
     .enter().append("circle") 
     .attr("class", "node") 
     .attr("r", 5) 
     .attr("fill", "blue") 
     .call(d3.drag() 
      .on("start", dragstarted) 
      .on("drag", dragged) 
      .on("end", dragended)); 
} 

function drawMainNode(nodes) { 
    return svg.selectAll("circle.mainnode") 
     .data(nodes, function (d, i) { return d.Id; }) 
     .enter().append("circle") 
     .attr("class", "mainnode") 
     .attr("r", 15) 
     .attr("fill", "red") 
     .call(d3.drag() 
      .on("start", dragstarted) 
      .on("drag", dragged) 
      .on("end", dragended)); 
} 

function drawLinks(links) { 
    return svg.selectAll("line") 
     .data(links, function (d, i) { return d.source + "-" + d.target; }) 
     .enter().append("line") 
     .attr("stroke-width", 3); 
} 

function dragstarted(d) { 
    if (!d3.event.active) dragSimualtion.alphaTarget(0.3).restart(); 
    d.fx = d.x; 
    d.fy = d.y; 
} 

function dragged(d) { 
    d.fx = d3.event.x; 
    d.fy = d3.event.y; 
} 

function dragended(d) { 
    if (!d3.event.active) dragSimualtion.alphaTarget(0); 
    d.fx = null; 
    d.fy = null; 
} 

function ticked() { 
    dLinks 
     .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; }); 

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

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

var dLinks = drawLinks(mainLinks.concat(nodeLinks)); 
var dNodes = drawNode(nodes); 
var dMainNodes = drawMainNode(mainNodes); 

var simulation = d3.forceSimulation(mainNodes.concat(nodes)) 
       .force("charge", d3.forceManyBody()) 
       .force("center", d3.forceCenter(width/2, height/2)) 
       .force("collide", d3.forceCollide(20).radius(20)) 
       .force("links", d3.forceLink(mainLinks.concat(nodeLinks)) 
        .id(function (d) { return d.Id; })) 
       .alpha(0.9) 
       .alphaDecay(0.1) 
       .on("tick", ticked); 

var dragSimualtion = d3.forceSimulation(mainNodes.concat(nodes)) 
       .force("collide", d3.forceCollide(20).radius(20)) 
       .force("links", d3.forceLink(mainLinks.concat(nodeLinks)) 
        .id(function (d) { return d.Id; })) 
       .alphaDecay(0.1) 
       .on("tick", ticked) 
       .stop() 

Plunkr

我試圖用一個單獨的模擬拖事件只使用鏈接力和碰撞力 - 因爲節點應該與附屬於它們的每個節點一起拖動,而其他非附加節點應該被推開,但只有在它們相互碰撞時纔會被推開。

所以問題是,我如何防止其他節點飛來飛去?

EDIT1:我第一次嘗試使用只有第一個模擬對象,但我認爲觀察到的效果是由d3.forceManyBody由於其斥力而引起的。我試圖用distanceMax來限制這種影響,但沒有成功。我的第二次嘗試是使用單獨的d3.forceSimulation,它只包含與拖動動畫相關的力。

+0

這可能是因爲'd3.forceManyBody'和'd3.forceCollide'的組合。我真的不認爲你需要單獨的模擬拖動事件。只需更新默認的一個。見https://bl.ocks.org/mbostock/2675ff61ea5e063ede2b5d63c08020c7 – mahish

+0

我的第一次嘗試是隻使用一個模擬,但我認爲節點的漂移效應是由ManyBody力(由於斥力)引起的,所以我創建了第二次模擬。我也嘗試用d3.forceManyBody的disferentialMax()來將排斥力限制在一定範圍內。 –

回答

0

拖拽功能的forceCollide似乎是問題...

嘗試:

.force("collide", d3.forceCollide(20).radius(20).strength(0)) 

那麼你得到相反的問題,那麼在0和1之間的嘗試,找到一個你喜歡的。