|
1 <!DOCTYPE html> |
|
2 <html> |
|
3 <head> |
|
4 <title>Force-Directed Layout (Dynamic)</title> |
|
5 <script type="text/javascript" src="../../d3.js"></script> |
|
6 <script type="text/javascript" src="../../d3.geom.js"></script> |
|
7 <script type="text/javascript" src="../../d3.layout.js"></script> |
|
8 <style type="text/css"> |
|
9 |
|
10 rect { |
|
11 fill: #fff; |
|
12 } |
|
13 |
|
14 .node { |
|
15 fill: #000; |
|
16 } |
|
17 |
|
18 .cursor { |
|
19 fill: none; |
|
20 stroke: brown; |
|
21 pointer-events: none; |
|
22 } |
|
23 |
|
24 .link { |
|
25 stroke: #999; |
|
26 } |
|
27 |
|
28 </style> |
|
29 </head> |
|
30 <body> |
|
31 <div id="chart"></div> |
|
32 <script type="text/javascript"> |
|
33 |
|
34 var w = 960, |
|
35 h = 500, |
|
36 fill = d3.scale.category20(), |
|
37 nodes = [], |
|
38 links = []; |
|
39 |
|
40 var vis = d3.select("#chart").append("svg:svg") |
|
41 .attr("width", w) |
|
42 .attr("height", h); |
|
43 |
|
44 vis.append("svg:rect") |
|
45 .attr("width", w) |
|
46 .attr("height", h); |
|
47 |
|
48 var force = d3.layout.force() |
|
49 .distance(30) |
|
50 .nodes(nodes) |
|
51 .links(links) |
|
52 .size([w, h]); |
|
53 |
|
54 var cursor = vis.append("svg:circle") |
|
55 .attr("r", 30) |
|
56 .attr("transform", "translate(-100,-100)") |
|
57 .attr("class", "cursor"); |
|
58 |
|
59 force.on("tick", function() { |
|
60 vis.selectAll("line.link") |
|
61 .attr("x1", function(d) { return d.source.x; }) |
|
62 .attr("y1", function(d) { return d.source.y; }) |
|
63 .attr("x2", function(d) { return d.target.x; }) |
|
64 .attr("y2", function(d) { return d.target.y; }); |
|
65 |
|
66 vis.selectAll("circle.node") |
|
67 .attr("cx", function(d) { return d.x; }) |
|
68 .attr("cy", function(d) { return d.y; }); |
|
69 }); |
|
70 |
|
71 vis.on("mousemove", function() { |
|
72 cursor.attr("transform", "translate(" + d3.svg.mouse(this) + ")"); |
|
73 }); |
|
74 |
|
75 vis.on("mousedown", function() { |
|
76 var point = d3.svg.mouse(this), |
|
77 node = {x: point[0], y: point[1]}, |
|
78 n = nodes.push(node); |
|
79 |
|
80 // add links to any nearby nodes |
|
81 nodes.forEach(function(target) { |
|
82 var x = target.x - node.x, |
|
83 y = target.y - node.y; |
|
84 if (Math.sqrt(x * x + y * y) < 30) { |
|
85 links.push({source: node, target: target}); |
|
86 } |
|
87 }); |
|
88 |
|
89 restart(); |
|
90 }); |
|
91 |
|
92 restart(); |
|
93 |
|
94 function restart() { |
|
95 force.start(); |
|
96 |
|
97 vis.selectAll("line.link") |
|
98 .data(links) |
|
99 .enter().insert("svg:line", "circle.node") |
|
100 .attr("class", "link") |
|
101 .attr("x1", function(d) { return d.source.x; }) |
|
102 .attr("y1", function(d) { return d.source.y; }) |
|
103 .attr("x2", function(d) { return d.target.x; }) |
|
104 .attr("y2", function(d) { return d.target.y; }); |
|
105 |
|
106 vis.selectAll("circle.node") |
|
107 .data(nodes) |
|
108 .enter().insert("svg:circle", "circle.cursor") |
|
109 .attr("class", "node") |
|
110 .attr("cx", function(d) { return d.x; }) |
|
111 .attr("cy", function(d) { return d.y; }) |
|
112 .attr("r", 4.5) |
|
113 .call(force.drag); |
|
114 } |
|
115 |
|
116 </script> |
|
117 </body> |
|
118 </html> |