An example of how to embed two force-diagrams in the same svg.
This was a question I saw on stackoverflow and was trying to figure out for myself - hopefully it's helpful.
license: mit |
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
</style> | |
</head> | |
<body> | |
<script> | |
const width = 1000 | |
const height = 600 | |
const svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height) | |
const roleScale = d3.scaleOrdinal() | |
.range(['coral', 'olive', 'skyblue', 'pink']); | |
const roleScale2 = d3.scaleOrdinal() | |
.range(['red', 'orange', 'green', 'blue']); | |
let sampleData = d3.range(4).map((d,i) => ({r: 40 - i * 0.5})); | |
let sampleData2 = d3.range(4).map((d,i) => ({r: 40 - i * 0.5})); | |
function force1(data) { | |
const manyBody = d3.forceManyBody().strength(2) | |
const center = d3.forceCenter().x((width/1.5)).y((height/4.5)) | |
// define force | |
let force = d3.forceSimulation() | |
.force('charge', manyBody) | |
.force('center', center) | |
.force('collision', d3.forceCollide(d => d.r + 2)) | |
.velocityDecay(.48) | |
.nodes(data) | |
.on('tick', changeNetwork) | |
svg.selectAll('circle') | |
.data(data) | |
.enter() | |
.append('circle') | |
.attr('class', 'force1') | |
.style('fill', (d,i) => roleScale(i)) | |
.attr('r', d => d.r) | |
function changeNetwork() { | |
d3.selectAll('circle.force1') | |
.attr('cx', d => d.x) | |
.attr('cy', d => d.y) | |
} | |
} | |
function force2(data) { | |
const manyBody = d3.forceManyBody().strength(2) | |
const center = d3.forceCenter().x((width/2.5)).y((height/2)) | |
// define force | |
let force = d3.forceSimulation() | |
.force('charge', manyBody) | |
.force('center', center) | |
.force('collision', d3.forceCollide(d => d.r + 2)) | |
.velocityDecay(.48) | |
.nodes(data) | |
.on('tick', changeNetwork2) | |
svg.selectAll('circle.force2') | |
.data(data) | |
.enter() | |
.append('circle') | |
.attr('class', 'force2') | |
.style('fill', (d,i) => roleScale2(i)) | |
.attr('r', d => d.r) | |
function changeNetwork2() { | |
d3.selectAll('.force2') | |
.attr('cx', d => d.x) | |
.attr('cy', d => d.y) | |
} | |
} | |
// call funcs | |
force1(sampleData); | |
force2(sampleData2); | |
</script> | |
</body> |