2016-08-18 70 views
0

我是新與d3.js碰撞,我想要做的是接近這個:http://codepen.io/fabiobiondi/pen/nFxyD手柄,d3.js多竈力佈局

// GROUPS: 0 Web | 1: Adobe | 2: hybrid 
var data = [ 
    {"id": 0, "name": "AngularJS", "r": 50 }, 
    {"id": 0, "name": "HTML5", "r": 40 }, 
    {"id": 0, "name": "Javascript", "r": 30 }, 
    {"id": 0, "name": "NodeJs", "r": 30 }, 
    {"id": 0, "name": "D3.js", "r": 40 }, 
    {"id": 0, "name": "CreateJS", "r": 45 }, 
    {"id": 0, "name": "Cordova", "r": 40 }, 
    {"id": 0, "name": "CSS", "r": 40 }, 
    {"id": 0, "name": "SVG", "r": 20 }, 
    {"id": 0, "name": "PHP", "r": 20 }, 
    {"id": 0, "name": "jQuery", "r": 30 }, 

    {"id": 1, "name": "Actionscript", "r": 50 }, 
    {"id": 1, "name": "Flash", "r": 32 }, 
    {"id": 1, "name": "Flex", "r": 50 }, 
    {"id": 1, "name": "AIR", "r": 40 }, 
    {"id": 1, "name": "Photoshop", "r": 30 }, 
    {"id": 1, "name": "Illustrator", "r": 30 }, 

    {"id": 2, "name": "Node Webkit", "r": 40 }, 
    {"id": 2, "name": "Chrome App", "r": 30 }, 
    {"id": 2, "name": "Cordova", "r": 45 }, 
]; 

var width = window.innerWidth, 
    height = 450; 

var fill = d3.scale.category10(); 

var nodes = [], labels = [], 
    foci = [{x: 0, y: 150}, {x: 350, y: 150}, {x: 200, y: 150}]; 

var svg = d3.select("body").append("svg") 
    .attr("width", "100%") 
    .attr("height", height) 
    //.attr("domflag", ''); 

var force = d3.layout.force() 
    .nodes(nodes) 
    .links([]) 
    .charge(-400) 
    //.chargeDistance(200) 
    .gravity(0.1) 
    .friction(0.8) 
    .size([width, height]) 
    .on("tick", tick); 

//var node = svg.selectAll("circle"); 
var node = svg.selectAll("g"); 

var counter = 0; 

function tick(e) { 
    var k = .1 * e.alpha; 

    // Push nodes toward their designated focus. 
    nodes.forEach(function(o, i) { 
    o.y += (foci[o.id].y - o.y) * k; 
    o.x += (foci[o.id].x - o.x) * k; 
    }); 

    node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 

} 


var timer = setInterval(function(){ 

    if (nodes.length > data.length-1) { clearInterval(timer); return;} 

    var item = data[counter]; 
    nodes.push({id: item.id, r: item.r, name: item.name}); 
    force.start(); 

    node = node.data(nodes); 

    var n = node.enter().append("g") 
     .attr("class", "node") 
     .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) 
     .style('cursor', 'pointer') 
     .on('mousedown', function() { 
     var sel = d3.select(this); 
     sel.moveToFront(); 
     }) 
     .call(force.drag); 

    n.append("circle") 
     .attr("r", function(d) { return d.r; }) 
     .style("fill", function(d) { return fill(d.id); }) 

    n.append("text") 
     .text(function(d){ 
      return d.name; 
     }) 
     .style("font-size", function(d) { 
      return Math.min(2 * d.r, (2 * d.r - 8)/this.getComputedTextLength() * 16) + "px"; 
     }) 
     .attr("dy", ".35em") 

    counter++; 
}, 100); 


d3.selection.prototype.moveToFront = function() { 
    return this.each(function(){ 
    this.parentNode.appendChild(this); 
    }); 
}; 

function resize() { 
    width = window.innerWidth; 
    force.size([width, height]); 
    force.start(); 
} 

d3.select(window).on('resize', resize); 

我不明白的是我怎樣才能控制圈子可以或不可以碰撞的方式。

我曾嘗試碰撞這樣的功能https://bl.ocks.org/mbostock/1804919但我不明白它的工作原理。當我改變填充值時,圈子不斷避免自己。我想要的是允許碰撞,但不要太多(比如說10px),以確保裏面的文本永遠不會被隱藏。

回答

1

我已經實現了這個例子:https://bl.ocks.org/mbostock/7881887

我加了碰撞功能:

// Resolves collisions between d and all other circles. 
function collide(alpha) { 
    var quadtree = d3.geom.quadtree(nodes); 
    return function(d) { 
    //console.log(d) 
    var r = d.r + maxRadius + Math.max(padding, clusterPadding), 
     nx1 = d.x - r, 
     nx2 = d.x + r, 
     ny1 = d.y - r, 
     ny2 = d.y + r; 
    quadtree.visit(function(quad, x1, y1, x2, y2) { 
     if (quad.point && (quad.point !== d)) { 
     var x = d.x - quad.point.x, 
      y = d.y - quad.point.y, 
      l = Math.sqrt(x * x + y * y), 
      r = d.r + quad.point.r + (d.cluster === quad.point.cluster ? padding : clusterPadding); 
     if (l < r) { 
      l = (l - r)/l * alpha; 
      d.x -= x *= l; 
      d.y -= y *= l; 
      quad.point.x += x; 
      quad.point.y += y; 
     } 
     } 
     return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; 
    }); 
    }; 
} 

這是所有的鏈接上面的解釋,所以我不會在這裏需要解釋一下。

在這個例子中其d.radius但你必須d.r.Also的maxRadius我摸索出這樣的:

var maxRadius = data.reduce(function(sum, d){ 
    return Math.max(sum,d.r) 
}, 0); //get maximum radius 

以上降低了數據陣列,並得到R(半徑)的最大價值。他們是我所做的唯一改變。

而且我已經更新您的滴答聲功能:

function tick(e) { 
    var k = .1 * e.alpha; 

    // Push nodes toward their designated focus. 
    nodes.forEach(function(o, i) { 
    // console.log(o) 
    o.y += (foci[o.id].y - o.y) * k; 
    o.x += (foci[o.id].x - o.x) * k; 
    }); 

    node 
    .each(collide(.5)) //call collide function here 
    .attr("cx", function(d) { return d.x; }) 
     .attr("cy", function(d) { return d.y; }) 
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 

} 

這需要多竈你有和碰撞檢測的照顧。

更新小提琴:https://jsfiddle.net/thatOneGuy/392kwuru/

+0

我用小提琴所有的時間和不喜歡codepen的佈局,只是如果youre想知道爲什麼我去的那:)希望幫助 – thatOneGuy

+0

太感謝你了,我不能說到目前爲止,我已經理解了,但是當我將負值變爲填充時,我得到了我想要的。我正在研究這個另一個例子:https://bl.ocks.org/mbostock/2990a882e007f8384b04827617752738,是不是一個更簡單的方法來做到這一點與v4? – sam