chart = {
var nodeRadius = 4;
var linkWidth = d3.scaleLinear().range([1.5, 2 * nodeRadius]);
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
};
var width = 960 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom().scale(x);
var yAxis = d3.axisLeft().scale(y);
var svgDOM = d3.select(DOM.svg(960, 500))
.attr('class', 'semanticsubstrate')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom);
var svg = svgDOM.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var graph = data;
var idToNode = {};
graph.nodes.forEach(function (n) {
n.degree = 0;
idToNode[n.id] = n;
});
graph.links.forEach(function (e) {
e.source = idToNode[e.source];
e.target = idToNode[e.target];
e.source.degree++;
e.target.degree++;
});
x.domain([0, d3.max(graph.nodes, function (d) { return d.chapters.length; })]);
y.domain([0, d3.max(graph.nodes, function (d) { return d.degree; })]);
linkWidth.domain(d3.extent(graph.links, function (d) { return d.chapters.length; }));
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis)
.append('text')
.attr('class', 'label')
.attr('x', width)
.attr('y', -6)
.text('Number of appearances');
svg.append('g')
.attr('class', 'y axis')
.call(yAxis)
.append('text')
.attr('class', 'label')
.attr('y', 6)
.attr('dy', '.71em')
.attr('transform', 'rotate(-90)')
.text('Number of interactions');
svg.selectAll('.tick line, .axis path')
.attr('stroke', '#999');
svg.selectAll('.tick text')
.attr('fill', '#777');
var link = svg.append('g')
.attr('class', 'links')
.selectAll('line')
.data(graph.links)
.enter().append('line')
.attr('x1', function (d) { return x(d.source.chapters.length); })
.attr('x2', function (d) { return x(d.target.chapters.length); })
.attr('y1', function (d) { return y(d.source.degree); })
.attr('y2', function (d) { return y(d.target.degree); })
.attr('stroke-width', function (d) { return linkWidth(d.chapters.length); })
.on('mouseover', function (d) {
link.style('stroke', null);
d3.select(this).style('stroke', '#d62333');
node.style('fill', function (node_d) {
return node_d === d.source || node_d === d.target ? 'black' : null;
});
})
.on('mouseout', function (d) {
link.style('stroke', null);
node.style('fill', null);
});
var node = svg.append('g')
.attr('class', 'nodes')
.selectAll('circle')
.data(graph.nodes)
.enter().append('circle')
.attr('cx', function (d) {
return (d.degree == 0 ? (Math.random() - 0.5) * nodeRadius : 0) + x(d.chapters.length);
})
.attr('cy', function (d) {
return (d.degree == 0 ? (Math.random() - 0.5) * nodeRadius : 0) + y(d.degree);
})
.attr('r', nodeRadius)
.on('mouseover', function (d) {
node.style('fill', null);
d3.select(this).style('fill', 'black');
var nodesToHighlight = graph.links.map(function (e) { return e.source === d ? e.target : e.target === d ? e.source : 0})
.filter(function (d) { return d; });
node.filter(function (d) { return nodesToHighlight.indexOf(d) >= 0; })
.style('fill', '#555');
link.style('stroke', function (link_d) {
return link_d.source === d || link_d.target === d ? '#d62333' : null;
});
})
.on('mouseout', function (d) {
node.style('fill', null);
link.style('stroke', null);
});
node.append('title').text(function (d) { return d.name; });
return svgDOM.node();
}