Building upon this svg based force layout with contours, but with canvas
xxxxxxxxxx
<meta charset="utf-8">
<style>
</style>
<canvas width="960" height="500"></canvas>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-contour.v1.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script>
var canvas = d3.select("canvas");
var width = canvas.attr("width");
var height = canvas.attr("height");
var context = canvas.node().getContext('2d');
var n = 400,
pi = Math.PI,
tau = 2 * pi,
radius = 32;
var nodes = d3.range(100).map(function() {
return { x: Math.random() * width, y: Math.random() * height };
});
context.fillStyle = '#333333';
context.strokeStyle = '#000000';
var path = d3.geoPath().context(context);
var data = d3.contourDensity()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.size([960, 960])
.thresholds([0.02])
.bandwidth(10)
(nodes)
var simulation = d3.forceSimulation()
.force("charge", d3.forceManyBody().strength(0.05))
.force("center", d3.forceCenter(width / 2, height / 2))
.alphaDecay(0)
.velocityDecay(0)
.nodes(nodes)
.on("tick", ticked);
function ticked() {
data = d3.contourDensity()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.size([960, 960])
.thresholds([0.02])
.bandwidth(10)
(nodes)
context.clearRect(0, 0, width, height);
context.fillStyle = '#d8d8d8';
context.strokeStyle = 'black';
context.beginPath();
path(data[0]);
context.fill();
context.stroke()
}
</script>
https://d3js.org/d3.v4.min.js
https://d3js.org/d3-contour.v1.min.js
https://d3js.org/d3-scale-chromatic.v1.min.js