|
graph = { |
|
nodes: [ |
|
{id: 'A', u: Math.random()}, |
|
{id: 'B', u: Math.random()}, |
|
{id: 'C', u: Math.random()}, |
|
{id: 'D', u: Math.random()}, |
|
{id: 'E', u: Math.random()}, |
|
{id: 'F', u: Math.random()}, |
|
{id: 'G', u: Math.random()}, |
|
{id: 'H', u: Math.random()}, |
|
{id: 'I', u: Math.random()}, |
|
{id: 'J', u: Math.random()}, |
|
{id: 'K', u: Math.random()}, |
|
{id: 'L', u: Math.random()}, |
|
{id: 'M', u: Math.random()}, |
|
{id: 'N', u: Math.random()}, |
|
{id: 'O', u: Math.random()} |
|
], |
|
links: [ |
|
{id: 1, source: 'A', target: 'B'}, |
|
{id: 2, source: 'B', target: 'C'}, |
|
{id: 3, source: 'C', target: 'A'}, |
|
{id: 4, source: 'B', target: 'D'}, |
|
{id: 5, source: 'D', target: 'C'}, |
|
{id: 6, source: 'D', target: 'E'}, |
|
{id: 7, source: 'E', target: 'F'}, |
|
{id: 8, source: 'F', target: 'G'}, |
|
{id: 9, source: 'F', target: 'H'}, |
|
{id: 10, source: 'G', target: 'H'}, |
|
{id: 11, source: 'G', target: 'I'}, |
|
{id: 12, source: 'H', target: 'I'}, |
|
{id: 13, source: 'J', target: 'E'}, |
|
{id: 14, source: 'J', target: 'L'}, |
|
{id: 15, source: 'J', target: 'K'}, |
|
{id: 16, source: 'K', target: 'L'}, |
|
{id: 17, source: 'L', target: 'M'}, |
|
{id: 18, source: 'M', target: 'K'}, |
|
{id: 19, source: 'N', target: 'O'} |
|
]} |
|
|
|
|
|
### objectify the graph ### |
|
### 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 |
|
|
|
if l.target is n.id |
|
l.target = n |
|
|
|
# link's u cannot exceed the ones of connected nodes |
|
l.u = Math.min(Math.random(), l.source.u, l.target.u) |
|
|
|
radius = d3.scale.sqrt() |
|
.domain([0,1]) |
|
.range([0,18]) |
|
|
|
thickness = d3.scale.linear() |
|
.domain([0,1]) |
|
.range([0,10]) |
|
|
|
svg = d3.select('svg') |
|
width = svg.node().getBoundingClientRect().width |
|
height = svg.node().getBoundingClientRect().height |
|
|
|
### create a crisp and a fuzzy layer ### |
|
crisp = svg.append('g') |
|
fuzzy = svg.append('g') |
|
|
|
### create crisp nodes ### |
|
|
|
nodes = crisp.selectAll('.node') |
|
.data(graph.nodes, (d) -> d.id) |
|
|
|
enter_crisp_nodes = nodes.enter().append('g') |
|
.attr |
|
class: 'crisp node' |
|
|
|
enter_crisp_nodes.append('circle') |
|
.attr |
|
r: radius.range()[1] |
|
|
|
enter_crisp_nodes.append('title') |
|
.text((d) -> "(#{d.id} #{d3.format('%')(d.u)})") |
|
|
|
### create fuzzy nodes and links ### |
|
links = fuzzy.selectAll('.link') |
|
.data(graph.links, (d) -> d.id) |
|
|
|
enter_fuzzy_links = links |
|
.enter().append('g') |
|
.attr |
|
class: 'fuzzy link' |
|
|
|
enter_fuzzy_links.append('line') |
|
.attr |
|
class: 'max' |
|
'stroke-width': (d) -> thickness(Math.min(d.source.u, d.target.u)) |
|
|
|
enter_fuzzy_links.append('line') |
|
.attr |
|
class: 'value' |
|
'stroke-width': (d) -> thickness(d.u) |
|
|
|
enter_fuzzy_links.append('title') |
|
.text((d) -> "(#{d.source.id})-[#{d3.format('%')(d.u)}]-(#{d.target.id})\nMax: #{d3.format('%')(Math.min(d.source.u,d.target.u))}") |
|
|
|
nodes = fuzzy.selectAll('.node') |
|
.data(graph.nodes, (d) -> d.id) |
|
|
|
enter_fuzzy_nodes = nodes.enter().append('g') |
|
.attr |
|
class: 'fuzzy node' |
|
|
|
enter_fuzzy_nodes.append('circle') |
|
.attr |
|
r: (d) -> radius(d.u) |
|
|
|
### draw the label ### |
|
enter_fuzzy_nodes.append('text') |
|
.text((d) -> d.id) |
|
.attr |
|
dy: '0.8em' |
|
x: (d) -> radius(d.u) |
|
y: (d) -> radius(d.u)/2 |
|
|
|
### cola layout ### |
|
graph.nodes.forEach (v) -> |
|
v.width = 2.5*radius(v.u) |
|
v.height = 2.5*radius(v.u) |
|
|
|
d3cola = cola.d3adaptor() |
|
.size([width, height]) |
|
.linkDistance(60) |
|
.avoidOverlaps(true) |
|
.nodes(graph.nodes) |
|
.links(graph.links) |
|
.on 'tick', () -> |
|
### update nodes and links ### |
|
svg.selectAll('.node') |
|
.attr('transform', (d) -> "translate(#{d.x},#{d.y})") |
|
|
|
svg.selectAll('.crisp.link > line') |
|
.attr('x1', (d) -> d.source.x) |
|
.attr('y1', (d) -> d.source.y) |
|
.attr('x2', (d) -> d.target.x) |
|
.attr('y2', (d) -> d.target.y) |
|
|
|
svg.selectAll('.fuzzy.link > line') |
|
.attr('x1', (d) -> d.source.x) |
|
.attr('y1', (d) -> d.source.y) |
|
.attr('x2', (d) -> d.target.x) |
|
.attr('y2', (d) -> d.target.y) |
|
|
|
enter_crisp_nodes |
|
.call(d3cola.drag) |
|
|
|
d3cola.start(30,30,30) |