Simulation of human movement from their places of birth
Built with blockbuilder.org
license: mit |
Simulation of human movement from their places of birth
Built with blockbuilder.org
<!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> | |
// Feel free to change or delete any of the code you see in this editor! | |
var canvas = d3.select("body").append("canvas") | |
.attr("width", 960) | |
.attr("height", 500); | |
var c = canvas.node().getContext("2d"), | |
r = 1.5; | |
var s = d3.scaleLinear() | |
.domain([0,1]) | |
.range([300,400]) | |
var nodes = d3.range(8000).map(d => ({})); | |
d3.forceSimulation(nodes) | |
.force('saute', function(alpha){ | |
nodes.forEach(d => { | |
if (Math.random() < 1e-2) { | |
var k = d3.randomLogNormal()(); | |
var alpha = k * 100000; | |
k = Math.sqrt(k); | |
d[0] = k * Math.cos(alpha); | |
d[1] = k * Math.sin(alpha); | |
d.c = true; | |
} | |
}); | |
}) | |
.alphaTarget(1e-12) | |
.on('tick', draw); | |
function draw() { | |
c.clearRect(0, 0, 960, 500); | |
var th = 0; | |
var sums = []; | |
nodes.forEach(function(d){ | |
d[2] = Math.sqrt(d[0]*d[0] + d[1]*d[1]); | |
var u = Math.floor(s(d[2])); | |
if (sums[u]) d[3] = (sums[u] = sums[u] - 0.01); | |
else d[3] = sums[u] = -0.001; | |
}); | |
c.fillStyle = 'black'; // d.c ? 'rgba(0,0,0,0.1)' : 'rgba(0,0,0,0.1)'; | |
c.beginPath(); | |
nodes.forEach(function(d) { | |
if (d.c) { | |
d.x = s(d[0]); | |
d.y = s(d[1]); | |
} else { | |
var k = 0.2 * Math.sqrt(th / nodes.length), alpha = th; | |
d.x = s(k * Math.cos(alpha)); | |
d.y = s(k * Math.sin(alpha)); | |
th++; | |
} | |
c.moveTo(d.x + r, d.y); | |
c.arc(d.x, d.y, r, 0, 2 * Math.PI); | |
}); | |
c.fill(); | |
c.beginPath(); | |
c.moveTo(s(0.2), s(0)); | |
c.arc(s(0), s(0), s(0.2)-s(0), 0, 2 * Math.PI); | |
c.stroke(); | |
c.beginPath(); | |
c.fillStyle = 'grey'; // d.c ? 'rgba(0,0,0,0.1)' : 'rgba(0,0,0,0.1)'; | |
nodes.forEach(function(d) { | |
if (d.c) { | |
d.x = s(d[2]); | |
d.y = 180+s(d[3]); | |
c.moveTo(d.x + r, d.y); | |
c.arc(d.x, d.y, r, 0, 2 * Math.PI); | |
} | |
}); | |
c.fill(); | |
} | |
</script> | |
</body> |