an es2015 d3v4 iteration on the block network fade from @jalapic
mouse over a node to see that node and it's first-degree neighbors highlighted (along with the links that connect them)
see also graph neighbors on mouseover from @micahstubbs
license: MIT | |
border: no | |
height: 750 |
online.html | |
offline.html | |
d3.min.js | |
d3.v4.js |
an es2015 d3v4 iteration on the block network fade from @jalapic
mouse over a node to see that node and it's first-degree neighbors highlighted (along with the links that connect them)
see also graph neighbors on mouseover from @micahstubbs
{ | |
"nodes": [ | |
{ | |
"name": "A", | |
"id": 0 | |
}, | |
{ | |
"name": "D", | |
"id": 1 | |
}, | |
{ | |
"name": "K", | |
"id": 2 | |
}, | |
{ | |
"name": "B", | |
"id": 3 | |
}, | |
{ | |
"name": "G", | |
"id": 4 | |
}, | |
{ | |
"name": "H", | |
"id": 5 | |
}, | |
{ | |
"name": "C", | |
"id": 6 | |
}, | |
{ | |
"name": "L", | |
"id": 7 | |
}, | |
{ | |
"name": "E", | |
"id": 8 | |
}, | |
{ | |
"name": "F", | |
"id": 9 | |
}, | |
{ | |
"name": "J", | |
"id": 10 | |
}, | |
{ | |
"name": "I", | |
"id": 11 | |
}, | |
{ | |
"name": "M", | |
"id": 12 | |
} | |
], | |
"links": [ | |
{ | |
"source": 0, | |
"target": 1, | |
"type": "high" | |
}, | |
{ | |
"source": 0, | |
"target": 2, | |
"type": "high" | |
}, | |
{ | |
"source": 3, | |
"target": 4, | |
"type": "high" | |
}, | |
{ | |
"source": 5, | |
"target": 3, | |
"type": "high" | |
}, | |
{ | |
"source": 6, | |
"target": 0, | |
"type": "low" | |
}, | |
{ | |
"source": 6, | |
"target": 7, | |
"type": "low" | |
}, | |
{ | |
"source": 8, | |
"target": 0, | |
"type": "low" | |
}, | |
{ | |
"source": 9, | |
"target": 3, | |
"type": "low" | |
}, | |
{ | |
"source": 9, | |
"target": 4, | |
"type": "low" | |
}, | |
{ | |
"source": 2, | |
"target": 10, | |
"type": "low" | |
}, | |
{ | |
"source": 9, | |
"target": 11, | |
"type": "low" | |
}, | |
{ | |
"source": 4, | |
"target": 5, | |
"type": "low" | |
}, | |
{ | |
"source": 8, | |
"target": 2, | |
"type": "high" | |
}, | |
{ | |
"source": 8, | |
"target": 4, | |
"type": "low" | |
}, | |
{ | |
"source": 8, | |
"target": 9, | |
"type": "high" | |
}, | |
{ | |
"source": 8, | |
"target": 12, | |
"type": "high" | |
} | |
] | |
} |
<!DOCTYPE html> | |
<meta charset='utf-8'> | |
<script src='http://d3js.org/d3.v4.js'></script> | |
<style> | |
.node circle { | |
fill: #DDD; | |
stroke: #777; | |
stroke-width: 2px; | |
} | |
.node text { | |
font-family: sans-serif; | |
text-anchor: middle; | |
pointer-events: none; | |
user-select: none; | |
-webkit-user-select: none; | |
} | |
.link { | |
stroke: #88A; | |
stroke-width: 4px; | |
} | |
text { | |
font: 18px sans-serif; | |
pointer-events: none; | |
} | |
#end-arrow { | |
fill: #88A; | |
} | |
</style> | |
<body> | |
<script src='vis.js'></script> | |
</body> | |
# safe | |
lebab --replace vis.js --transform arrow | |
lebab --replace vis.js --transform for-of | |
lebab --replace vis.js --transform for-each | |
lebab --replace vis.js --transform arg-rest | |
lebab --replace vis.js --transform arg-spread | |
lebab --replace vis.js --transform obj-method | |
lebab --replace vis.js --transform obj-shorthand | |
lebab --replace vis.js --transform multi-var | |
# unsafe | |
lebab --replace vis.js --transform let | |
lebab --replace vis.js --transform template |
/* global d3 */ | |
d3.json('graph.json', (error, graph) => { | |
const width = 960; | |
const height = 700; | |
const simulation = d3.forceSimulation() | |
.nodes(graph.nodes) | |
.force('link', d3.forceLink().id(d => d.id)) | |
.force('charge', d3.forceManyBody().strength([-250])) | |
.force('center', d3.forceCenter(width / 2, height / 2)) | |
.on('tick', ticked); | |
simulation.force('link') | |
.links(graph.links) | |
.distance([85]); | |
const R = 18; | |
const svg = d3.select('body').append('svg') | |
.attr('width', width) | |
.attr('height', height); | |
// add defs-marker | |
// add defs-markers | |
svg.append('svg:defs').selectAll('marker') | |
.data([{ id: 'end-arrow', opacity: 1 }, { id: 'end-arrow-fade', opacity: 0.1 }]) | |
.enter().append('marker') | |
.attr('id', d => d.id) | |
.attr('viewBox', '0 0 10 10') | |
.attr('refX', 2 + R) | |
.attr('refY', 5) | |
.attr('markerWidth', 4) | |
.attr('markerHeight', 4) | |
.attr('orient', 'auto') | |
.append('svg:path') | |
.attr('d', 'M0,0 L0,10 L10,5 z') | |
.style('opacity', d => d.opacity); | |
let link = svg.selectAll('line') | |
.data(graph.links) | |
.enter().append('line'); | |
link | |
.attr('class', 'link') | |
.attr('marker-end', 'url(#end-arrow)') | |
.on('mouseout', fade(1)); | |
let node = svg.selectAll('.node') | |
.data(graph.nodes) | |
.enter().append('g') | |
.attr('class', 'node'); | |
node.append('circle') | |
.attr('r', R) | |
.on('mouseover', fade(0.1)) | |
.on('mouseout', fade(1)) | |
.call(d3.drag() | |
.on("start", dragstarted) | |
.on("drag", dragged) | |
.on("end", dragended)); | |
node.append('text') | |
.attr('x', 0) | |
.attr('dy', '.35em') | |
.text(d => d.name); | |
function ticked() { | |
link | |
.attr('x1', d => d.source.x) | |
.attr('y1', d => d.source.y) | |
.attr('x2', d => d.target.x) | |
.attr('y2', d => d.target.y); | |
node | |
.attr('transform', d => `translate(${d.x},${d.y})`); | |
} | |
function dragstarted(d) { | |
if (!d3.event.active) simulation.alphaTarget(0.3).restart(); | |
d.fx = d.x; | |
d.fy = d.y; | |
} | |
function dragged(d) { | |
d.fx = d3.event.x; | |
d.fy = d3.event.y; | |
} | |
function dragended(d) { | |
if (!d3.event.active) simulation.alphaTarget(0); | |
d.fx = null; | |
d.fy = null; | |
} | |
const linkedByIndex = {}; | |
graph.links.forEach(d => { | |
linkedByIndex[`${d.source.index},${d.target.index}`] = 1; | |
}); | |
function isConnected(a, b) { | |
return linkedByIndex[`${a.index},${b.index}`] || linkedByIndex[`${b.index},${a.index}`] || a.index === b.index; | |
} | |
function fade(opacity) { | |
return d => { | |
node.style('stroke-opacity', function (o) { | |
const thisOpacity = isConnected(d, o) ? 1 : opacity; | |
this.setAttribute('fill-opacity', thisOpacity); | |
return thisOpacity; | |
}); | |
link.style('stroke-opacity', o => (o.source === d || o.target === d ? 1 : opacity)); | |
link.attr('marker-end', o => (opacity === 1 || o.source === d || o.target === d ? 'url(#end-arrow)' : 'url(#end-arrow-fade)')); | |
}; | |
} | |
}) |