2015-10-08 6 views
1

Я пытаюсь создать инфографику с использованием примера кластерного силового элемента III, и у меня это почти так, как я хочу, но мне нужно указать несколько узлов для каждого кластера. Кластер 1 - 10 узлов, кластер 2 - 7 узлов, кластер 3 - 11 узлов, кластер 4 - 18 узлов, кластер 5 - 16 узлов, кластер 6 - 19 узлов, кластер 7 - 42 узла, кластер 8 - 14 узлов. У меня есть правильное общее количество узлов и правильное общее количество кластеров, и я сделал все узлы того же размера. Теперь мне просто нужно нажать круги вокруг, чтобы представить данные. Мой код ниже.Задание числа узлов в каждом кластере кластерной силовой компоновки в d3js

var width = 175, 
    height = 175, 
    padding = 1.5, // separation between same-color nodes 
    clusterPadding = 6, // separation between different-color nodes 
    maxRadius = 4; 

var n = 137, // total number of nodes 
    m = 8; // number of distinct clusters 

var color = d3.scale.category10() 
    .domain(d3.range(m)); 

// The largest node for each cluster. 
var clusters = new Array(m); 

var nodes = d3.range(n).map(function() { 
    var i = Math.floor(Math.random() * m), 
     r = maxRadius, 
     d = { 
     cluster: i, 
     radius: r, 
     x: Math.cos(i/m * 2 * Math.PI) * 200 + width/2 + Math.random(), 
     y: Math.sin(i/m * 2 * Math.PI) * 200 + height/2 + Math.random() 
     }; 
    if (!clusters[i] || (r > clusters[i].radius)) clusters[i] = d; 
    return d; 
}); 

var force = d3.layout.force() 
    .nodes(nodes) 
    .size([width, height]) 
    .gravity(.02) 
    .charge(0) 
    .on("tick", tick) 
    .start(); 

var svg = d3.select(".wpd3-1042-0").append("svg") 
    .attr("width", width) 
    .attr("height", height); 

var node = svg.selectAll("circle") 
    .data(nodes) 
    .enter().append("circle") 
    .style("fill", function(d) { return color(d.cluster); }) 
    .call(force.drag); 

node.transition() 
    .duration(750) 
    .delay(function(d, i) { return i * 5; }) 
    .attrTween("r", function(d) { 
     var i = d3.interpolate(0, d.radius); 
     return function(t) { return d.radius = i(t); }; 
    }); 

function tick(e) { 
    node 
     .each(cluster(10 * e.alpha * e.alpha)) 
     .each(collide(.5)) 
     .attr("cx", function(d) { return d.x; }) 
     .attr("cy", function(d) { return d.y; }); 
} 

// Move d to be adjacent to the cluster node. 
function cluster(alpha) { 
    return function(d) { 
    var cluster = clusters[d.cluster]; 
    if (cluster === d) return; 
    var x = d.x - cluster.x, 
     y = d.y - cluster.y, 
     l = Math.sqrt(x * x + y * y), 
     r = d.radius + cluster.radius; 
    if (l != r) { 
     l = (l - r)/l * alpha; 
     d.x -= x *= l; 
     d.y -= y *= l; 
     cluster.x += x; 
     cluster.y += y; 
    } 
    }; 
} 

// Resolves collisions between d and all other circles. 
function collide(alpha) { 
    var quadtree = d3.geom.quadtree(nodes); 
    return function(d) { 
    var r = d.radius + 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.radius + quad.point.radius + (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; 
    }); 
    }; 
} 

ответ

0

Да! Вы можете достичь этого, делая что-то вроде этого:

var clusterNumber = [10, 7, 11, 18, 16, 19, 42, 14];//your cluster number of node array 
var n = d3.sum(clusterNumber, function (d) { 
    return d 
}); /// total number of nodes 

var m = clusterNumber.length;//total number of clusters 
var color = d3.scale.category10() 
    .domain(d3.range(m)); 

// The largest node for each cluster. 
var clusters = new Array(m); 
var nodes = []; 
clusterNumber.forEach(function (cn, i) { 
//this will make a cluster 
    var r = maxRadius; 
    for (var j = 0; j < cn; j++) { 
//this loop will make all the nodes 
     var d = { 
      cluster: i, 
      radius: r, 
      x: Math.cos(i/m * 2 * Math.PI) * 200 + width/2 + Math.random(), 
      y: Math.sin(i/m * 2 * Math.PI) * 200 + height/2 + Math.random() 
     }; 
     if (!clusters[i] || (r > clusters[i].radius)) clusters[i] = d; 
     nodes.push(d); 
    } 

}); 

Полных рабочего код here

Надеется, что это помогает!

+0

Большое спасибо Кирилл! – Dina

+0

@ Дина, если это поможет, пожалуйста, примите это как ответ :) – Cyril

+0

Выполнено. Еще раз спасибо! – Dina

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

  • Нет связанных вопросов^_^