JSFiddle - React, Tailwind, and code Playground
by jcubed111
HTML
<canvas width=500 height=500 id=main></canvas>
<div id="count"></div>
CSS
body{
background: #123;
color: #eee;
}
JavaScript
const ctx = document.getElementById('main').getContext('2d');
class Point{
constructor(x, y) {
this.x = x;
this.y = y;
this.adjacents = [];
this.marked = false;
}
*[Symbol.iterator]() {
yield this.x;
yield this.y;
}
markRecursive() {
this.marked = true;
this.adjacents.filter(q => !q.marked).forEach(q => q.markRecursive());
}
}
function pointDist([x1, y1], [x2, y2]) {
return Math.sqrt((x1-x2)**2 + (y1-y2)**2);
}
let points = [];
let w = 500, h = 500;
let r = 35;
for(let i=0; i < w*h/r/r; i++) {
let testPoint = new Point(
r + Math.random() * (w - 2*r),
r + Math.random() * (h - 2*r),
);
if(points.every(p => pointDist(testPoint, p) >= 2*r)) {
points.push(testPoint);
}
}
// connect close point
points.forEach(p => points.filter(
q => p != q && pointDist(p, q) < 3.5*r
).forEach(
q => p.adjacents.push(q)
));
// remove loose points
points.find(p => p.adjacents.length > 4).markRecursive();
points = points.filter(p => p.marked); // typically this removes < 1 point
function render() {
ctx.clearRect(0, 0, w, h);
points.forEach(p => {
ctx.fillStyle = p.marked ? '#bbb' : '#f22';
ctx.beginPath();
ctx.arc(...p, 5, 0, Math.PI*2);
ctx.fill();
ctx.setLineDash([5]);
ctx.beginPath();
ctx.strokeStyle = '#888';
p.adjacents.filter(q => p.x < q.x).forEach(q => {
ctx.moveTo(...p);
ctx.lineTo(...q);
});
ctx.stroke();
// ctx.strokeStyle = '#000';
// ctx.beginPath();
// ctx.arc(...p, r, 0, Math.PI*2);
// ctx.stroke();
})
}
render();
document.getElementById('count').innerText = points.length;