|
window.main = () -> |
|
width = 960 |
|
height = 500 |
|
|
|
### create the SVG ### |
|
vis = d3.select('body').append('svg') |
|
.attr('width', width) |
|
.attr('height', height) |
|
|
|
### prepare nodes and links selections ### |
|
nodes = vis.selectAll('.node') |
|
links = vis.selectAll('.link') |
|
|
|
### initialize the force layout ### |
|
force = d3.layout.force() |
|
.size([width, height]) |
|
.charge(-400) |
|
.linkDistance(40) |
|
.on('tick', (() -> |
|
### update nodes and links ### |
|
nodes |
|
.attr('transform', (d) -> "translate(#{d.x},#{d.y})") |
|
|
|
links |
|
.attr('x1', (d) -> d.source.x) |
|
.attr('y1', (d) -> d.source.y) |
|
.attr('x2', (d) -> d.target.x) |
|
.attr('y2', (d) -> d.target.y) |
|
|
|
)) |
|
|
|
### define a drag behavior to drag nodes ### |
|
### dragged nodes become fixed ### |
|
drag = force.drag() |
|
.on('dragstart', (d) -> d.fixed = true) |
|
|
|
### create some fake data ### |
|
graph = { |
|
'nodes': [ |
|
{'id': 'A', 'x': 469, 'y': 410}, |
|
{'id': 'B', 'x': 493, 'y': 364}, |
|
{'id': 'C', 'x': 442, 'y': 365}, |
|
{'id': 'D', 'x': 467, 'y': 314}, |
|
{'id': 'E', 'x': 477, 'y': 248}, |
|
{'id': 'F', 'x': 425, 'y': 207}, |
|
{'id': 'G', 'x': 402, 'y': 155}, |
|
{'id': 'H', 'x': 369, 'y': 196}, |
|
{'id': 'I', 'x': 350, 'y': 148}, |
|
{'id': 'J', 'x': 539, 'y': 222}, |
|
{'id': 'K', 'x': 594, 'y': 235}, |
|
{'id': 'L', 'x': 582, 'y': 185}, |
|
{'id': 'M', 'x': 633, 'y': 200} |
|
], |
|
'links': [ |
|
{'source': 'A', 'target': 'B'}, |
|
{'source': 'B', 'target': 'C'}, |
|
{'source': 'C', 'target': 'A'}, |
|
{'source': 'B', 'target': 'D'}, |
|
{'source': 'D', 'target': 'C'}, |
|
{'source': 'D', 'target': 'E'}, |
|
{'source': 'E', 'target': 'F'}, |
|
{'source': 'F', 'target': 'G'}, |
|
{'source': 'F', 'target': 'H'}, |
|
{'source': 'G', 'target': 'H'}, |
|
{'source': 'G', 'target': 'I'}, |
|
{'source': 'H', 'target': 'I'}, |
|
{'source': 'J', 'target': 'E'}, |
|
{'source': 'J', 'target': 'L'}, |
|
{'source': 'J', 'target': 'K'}, |
|
{'source': 'K', 'target': 'L'}, |
|
{'source': 'L', 'target': 'M'}, |
|
{'source': 'M', 'target': 'K'} |
|
] |
|
} |
|
|
|
### resolve node IDs (not optimized at all!) ### |
|
for l in graph.links |
|
for n in graph.nodes |
|
if l.source is n.id |
|
l.source = n |
|
continue |
|
|
|
if l.target is n.id |
|
l.target = n |
|
continue |
|
|
|
### create nodes and links ### |
|
### (links are drawn first to make them appear under the nodes) ### |
|
### also, overwrite the selections with their databound version ### |
|
links = links |
|
.data(graph.links) |
|
.enter().append('line') |
|
.attr('class', 'link') |
|
|
|
nodes = nodes |
|
.data(graph.nodes) |
|
.enter().append('g') |
|
.attr('class', 'node') |
|
.call(drag) |
|
|
|
nodes.append('circle') |
|
.attr('r', 12) |
|
|
|
### draw the label ### |
|
nodes.append('text') |
|
.text((d) -> d.id) |
|
.attr('dy', '0.35em') |
|
|
|
### run the force layout ### |
|
force |
|
.nodes(graph.nodes) |
|
.links(graph.links) |
|
.start() |
|
|