var width = 960, height = 500, padding = 2, min_padding = 0, max_padding = 50, maxRadius = 17, n = 200; var points = [ [18.5,15.7826087], [18.5,15.1630435 ], [18.5,14.75 ], [17.8928571,13.3043478 ], [17.4880952,12.2717391 ], [13.8452381,4.63043478 ], [12.6309524,2.35869565 ], [11.8214286,0.913043478 ], [11.0119048,0.5 ], [10,0.5 ], [8.98809524,0.5 ], [8.17857143,0.913043478 ], [7.36904762,2.35869565 ], [6.15476191,4.63043478], [2.51190476,12.2717391 ], [2.10714286,13.3043478 ], [1.5,14.75 ], [1.5,15.1630435], [1.5,15.7826087 ], [1.5,18.4673913 ], [3.52380952,19.5 ], [5.14285714,19.5 ], [8.78571429,19.5 ], [12.8333333,13.5108696], [12.8333333,10.5 ], [12.8333333,9.17391304], [12.0238097,7.52173913 ], [10,7.5 ], [7.97619034,7.52173913 ], [7.16666667,9.17391304 ], [7.16666667,10.5 ], [7.16666667,13.5108696], [11.2142857,19.5 ], [14.8571429,34.5 ], [16.4761905,19.5 ], [18.5,18.4673913 ], [18.5,15.7826087] ]; var nodes = points.map(function(d, i) { var r = Math.sqrt(1 / 1 * -Math.log(Math.random())) * maxRadius, p = {id: i, radius: r, cx: (d[0]*10) + 350, cy: (d[1]*10) + 150}; return p; }); nodes.forEach(function(d) { d.x = d.cx; d.y = d.cy; }); var voronoi = d3.geom.voronoi() .clipExtent([[-padding,-padding],[width+padding,height+padding]]) .x(function(d){ return d.x; }) .y(function(d){ return d.y; }); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var cells = svg.selectAll('.cell') .data(voronoi(nodes)); cells.enter().append('path') .attr('class', 'cell'); var circle = svg.selectAll("circle") .data(nodes); var enter_circle = circle.enter().append("circle") .attr('class', 'node'); enter_circle .attr("r", function(d) { return d.radius; }) .attr("cx", function(d) { return d.cx; }) .attr("cy", function(d) { return d.cy; }); var force = d3.layout.force() .nodes(nodes) .size([width, height]) .gravity(.02) .charge(0) .on("tick", tick) .start(); force.alpha(.05); function tick(e) { circle .each(gravity(.2 * e.alpha)) .each(collide(.5)) .attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }); cells .data(voronoi(nodes)); cells .attr('d', function(d){ if (d.length > 0) return "M" + d.join("L") + "Z"; else { return ''; } }); } /* SLIDER */ var x = d3.scale.linear() .domain([min_padding, max_padding]) .range([0, width/2]) .clamp(true); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(10, 10)") .call(d3.svg.axis() .scale(x) .ticks(0) .tickSize(0)) .select(".domain") .select(function() { return this.parentNode.appendChild(this.cloneNode(true)); }) .attr("class", "halo"); var brush = d3.svg.brush() .x(x) .extent([0, 0]) .on("brush", brushed); var slider = svg.append("g") .attr("class", "slider") .call(brush); slider.selectAll(".extent,.resize") .remove(); var handle = slider.append("circle") .attr("class", "handle") .attr("transform", "translate(10, 10)") .attr("r", 9); brush.extent([padding, padding]); slider .call(brush.event); function brushed() { var value = brush.extent()[0]; if (d3.event.sourceEvent) { value = x.invert(d3.mouse(this)[0]); brush.extent([value, value]); force.alpha(.01); } handle.attr("cx", x(value)); padding = value; } // Resolve collisions between nodes. function collide(alpha) { var quadtree = d3.geom.quadtree(nodes); return function(d) { var r = d.radius + maxRadius + padding, 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 + padding; 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; }); }; } // Move nodes toward cluster focus. function gravity(alpha) { return function(d) { d.y += (d.cy - d.y) * alpha; d.x += (d.cx - d.x) * alpha; }; }