var width = 960, height = 500; var color = d3.scale.category20(); var force = d3.layout.force() .charge(-100) .linkDistance(5) .size([width, height]); var svg = d3.select("#chart").append("svg") .attr("width", width) .attr("height", height); var tooltip = svg.append("text") .attr('dy', '15px') .attr('dx', '10px') .attr('class', 'tooltip'); d3.json("songs.json", function(songs) { var json = {}; json.nodes = []; var ids = {}; var radius = {}; for (var i = 0; i < songs.length; i++) { radius[songs[i].id] = 0; } for (var i = 0; i < songs.length; i++) { radius[songs[i].id] += 1; if (!ids.hasOwnProperty(songs[i].id)) { json.nodes.push(songs[i]); ids[songs[i].id] = json.nodes.length - 1; } } json.links = []; for (var i = 0; i < songs.length - 1; i++) { json.links.push({ source: ids[songs[i].id], target: ids[songs[i + 1].id] }); } force .nodes(json.nodes) .links(json.links) .start(); var link = svg.selectAll("line.link") .data(json.links) .enter().append("line") .attr("class", "link") .style("stroke-width", function(d) { return Math.sqrt(d.value); }); var node = svg.selectAll("circle.node") .data(json.nodes) .enter().append("circle") .attr("class", "node") .call(force.drag) .attr("r", function(d) { return (2.5 + radius[d.id]); }) .style("fill", function(d) { return color(d.artist); }) .on('mouseover', function(d) { tooltip.text(d.artist + ' - ' + d.name); }) .on('mouseout', function(d) { tooltip.text(''); }); node.append("title") .text(function(d) { return new Date(d.date * 1000); }); force.on("tick", function() { link.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; }); node.attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }); }); });