Published
Edited
Jul 31, 2018
1 fork
1 star
Insert cell
Insert cell
chart = {
var i, j, node;
var nodeSep = 20; //TODO: base on max link width.

var margin = {top: 20, right: 0, bottom: 30, left: 20};
var w = width - margin.left - margin.right;
var h = height - margin.top - margin.bottom;
const svg = d3.select(DOM.svg(width, height))
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var x = d3.scaleLinear().range([0, w]);

//Build a map to get a node by id.
var idToNode = {};
var graph = graph8am;
graph.nodes.forEach(function (n) {
idToNode[n.id] = n;
});
//Compute x, y coordinates for nodes
for(i = 0; i < graph.nodes.length; i++) {
node = graph.nodes[i];
node.x = nodeSep + i * (w - 4 * nodeSep) / (graph.nodes.length - 1);
node.y = h;
}
var linkWidth = d3.scaleLinear()
.domain(d3.extent(graph.links, function (d) { return parseInt(d.opens); }))
.range([1.5, 12]);
var link = svg.append('g')
.attr('class', 'links')
.selectAll('path')
.data(graph.links)
.enter().append('path')
.attr('d', drawArc)
/*
.attr('d', function (d) {
var source = idToNode[d.source];
var target = idToNode[d.target];

return ['M', source.x, h, 'A',
(source.x - target.x)/2, ',',
(source.x - target.x)/2, 0, 0, ',',
source.x < target.x ? 1 : 0, target.x, ',', h]
.join(' ');
})
*/
.attr('stroke-width', function (d) { return linkWidth(d.opens); })
.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.x; })
.attr('cy', function (d) { return d.y; })
.attr('r', function (d) { return 7; })
.attr('fill', circleColor)
.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.id ? e.target : 0});
//.map(function (e) { return e.source === d.id ? e.target : e.target === d.id ? e.source : 0});
node.filter(function (d) { return nodesToHighlight.indexOf(d.id) >= 0; })
.style('fill', '#555');
link.style('stroke', function (link_d) {
return link_d.source === d.id ? '#d62333' : null;
//return link_d.source === d.id | link_d.target === d.id ? '#d62333' : null;
});
})
.on('mouseout', function (d) {
node.style('fill', null);
link.style('stroke', null);
});

function circleColor(d) {
var nodesToHighlight = graph.links
.map(function (e) { return e.source === d.id ? e.target : 0});

if(nodesToHighlight.indexOf(d.id) >= 0) {
return '#d62333';
}
else {
return '#555';
}
}
//node.append('title').text(function (d) { return d.id; });

//labels
var text = svg.selectAll('text')
.data(graph.nodes)
.enter().append('text')
.attr('y', h + 18)
.attr('x', function(d) { return d.x - 11; })
.attr('class', 'arc-label')
.text(function(d) { return d.id; });
function drawArc(d) {
var source = idToNode[d.source];
var target = idToNode[d.target];

var draw = d3.line().curve(d3.curveBasis);
//Option 1.
//return draw([[source.x, source.y], [(target.x - source.x)/2, height/2], [target.x, target.y]]);

//Option 2.
/*
var midX = (source.x + target.x) / 2;
var midPercent = Math.abs(((source.x - target.x) / width));
var midY = height - (midPercent * height);
if(source.x > target.x) {
var midY = height + (midPercent * height);
}
return draw([[source.x, source.y], [midX, midY], [target.x, target.y]]);
*/
//Option 3.
var sw = linkWidth(d.opens);

var midX = (source.x + target.x) / 2;
var midY = h - target.x - source.x - sw;
var midY2 = h - target.x - source.x + sw;
//Special case for when source === target
if(source.id === target.id) {
return draw([
[source.x, h],
[source.x - 8, h/2],
[midX, 0],
[source.x + 8, h/2],
[target.x, h]]);
}
else {
return draw([
[source.x, h],
[midX, (midY > 0 ? midY : 0)],
// [target.x + (sw*1.5), 0],
// [target.x - (sw*1.5), 0],
// [midX, midY2],
[target.x, h]]);
}

//Option 4.
/*
var arc = d3.svg.arc()
.innerRadius(50)
.outerRadius(70)
.startAngle(45 * (Math.PI/180)) //convert from degs to radians
.endAngle(3) //just radians
*/
} //end: drawArc
return svg.node()
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more