// Chart Parameters var numNodes = 30, width = 600, height = 600, r = 15, b = 0.01; var c0 = '#FF6B6B', c1 = '#490A3D'; // Generate the nodes (data) var nodes = d3.range(numNodes).map(function(k) { return {num: k}; }), links = []; var circles, lines; // Compute the initial positions with the force layout var f0 = d3.layout.force() .size([width, height]) .nodes(nodes) .charge(-250) .start(); // Cool down the force while (f0.alpha() > 1e-5) { f0.tick(); } var svg = d3.select('.gravity'), gnodes = svg.select('g.nodes-container'), glinks = svg.select('g.links-container'); svg.attr('width', width).attr('height', height); var circles = gnodes.selectAll('circle.node').data(nodes); circles.enter().append('circle').classed('node', true); circles .attr('r', r) .attr('cx', function(d) { return d.x; }) .attr('cy', function(d) { return d.y; }) circles.exit().remove(); updateCircles(); // Compute the links with the voronoi triangulation links = d3.geom.voronoi() .x(function(d) { return d.x; }) .y(function(d) { return d.y; }) .links(nodes); var lines = glinks.selectAll('line.link').data(links); lines.enter().append('line').classed('link', true); lines.exit().remove(); var h = d3.scale.linear() .domain([0, Math.sqrt(width * width + height * height) / 2]) .range([2, 6]); var c = d3.scale.linear() .domain(h.domain()) .range([c0, c1]); updateLines(); function updateCircles() { circles .attr('cx', function(d) { return d.x; }) .attr('cy', function(d) { return d.y; }) .attr('fill', function(d) { return d.l ? c(d.l) : c0; }); } function updateLines() { lines .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; }) .attr('stroke', function(d) { if (d.source.l || d.target.l) { return d.source.l > d.target.l ? c(d.source.l) : c(d.target.l); } return c0; }); } var u = nodes[10]; nodes.forEach(function(d) { var dx = d.x - u.x, dy = d.y - u.y; var l = Math.sqrt(dx * dx + dy * dy); d.l = l; }); updateCircles(); updateLines(); circles.on('click', function(u) { nodes.forEach(function(d) { var dx = d.x - u.x, ux = dx / Math.abs(dx), dy = d.y - u.y, uy = dy / Math.abs(dy); var l = Math.sqrt(dx * dx + dy * dy); d.x = d.index !== u.index ? d.x + b * ux * h(l) : d.x; d.y = d.index !== u.index ? d.y + b * uy * h(l) : d.y; d.l = l; }); f0.resume(); }); f0.on('tick', function() { updateCircles(); updateLines(); });