Skip to content

Instantly share code, notes, and snippets.

@wegry
Last active August 31, 2016 12:23
Show Gist options
  • Save wegry/b0e78f4b7d712905693477f86fb6dd31 to your computer and use it in GitHub Desktop.
Save wegry/b0e78f4b7d712905693477f86fb6dd31 to your computer and use it in GitHub Desktop.
const sizeNode = d => d.value + 5
const fill = d3.scale.category10();
d3.json('file.json', function(error, top) {
const {nodes, links} = top
const parents = {}
links.forEach(link => {
let target = link.target
let source = link.source
let key = `${source},${target}`
parents[key] = 1
})
const {innerWidth, innerHeight} = window
var force = d3.layout.force()
.nodes(d3.values(nodes))
.size([innerWidth - 200, innerHeight - 200])
.links(links)
.gravity(.1)
.charge(d => d.value * -500)
.on('tick', tick)
.start();
// Set the range
var v = d3.scale.linear().range([0, 100]);
var svg = d3.select('body').append('svg')
.attr('width', innerWidth)
.attr('height', innerHeight);
// add the links and the arrows
const path = svg.append('svg:g').selectAll('path')
.data(force.links())
.enter().append('svg:path')
.attr('class', function(d) { return 'link ' + d.type; })
.attr('marker-end', 'url(#end)');
// define the nodes
const node = svg.selectAll('.node')
.data(force.nodes())
.enter().append('g')
.attr('class', 'node')
.on('mouseover', fade(.1))
.on('mouseout', fade(1))
.call(force.drag);
// add the nodes
node.append('circle')
.attr('index', d => d.index)
.attr('r', sizeNode)
.style('fill', d => fill(d.group));
// add the text
const text = node.append('text')
.attr('x', 12)
.attr('dy', '.35em')
.text(d => d.name);
const select = document.getElementById('searchNodes')
const indexedNodes = {}
nodes.forEach((n, index) => {
let options = select.options
options[index] = new Option(n.name, index)
indexedNodes[index] = node[index]
})
select.addEventListener('change', value => {
let selector = `circle[index='${select.value}']`
d3.select(selector)
.style('fill', 'red')
force.start()
})
select.addEventListener('mouseout', () => force.start())
select.addEventListener('mouseover', value => {
let selector = `circle[index='${select.value}']`
force.stop()
})
function areLinked(a, b) {
return parents[`${a.index},${b.index}`] ||
parents[`${b.index},${a.index}`] ||
a.index == b.index
}
function fade(opacity) {
return function(d) {
node.style("stroke-opacity", function(o) {
var thisOpacity = areLinked(d, o) ? 1 : opacity;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
path.style("stroke-opacity", opacity).style("stroke-opacity",
o => o.target === d || o.source === d ? 1 : opacity)
text.style('display', o => {
if (areLinked(d, o) || opacity == 1) {
return ''
}
return 'none'
})
}
}
// add the curvy lines
function tick() {
path.attr('d', function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return 'M' +
d.source.x + ',' +
d.source.y + 'A' +
dr + ',' + dr + ' 0 0,1 ' +
d.target.x + ',' +
d.target.y;
});
node
.attr('transform', function(d) {
d.x = Math.max(sizeNode(d), Math.min(innerWidth - sizeNode(d), d.x))
d.y = Math.max(sizeNode(d), Math.min(innerHeight - sizeNode(d), d.y))
return 'translate(' + d.x + ',' + d.y + ')'; });
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment