Public
Edited
Apr 26, 2023
6 forks
35 stars
Insert cell
Insert cell
Insert cell
{
replay;
const context = DOM.context2d(width, height);
context.fillStyle = "#fff";
context.fillRect(0, 0, width, height);
context.fillStyle = "#000";
for (let i = 1; i <= n; ++i) {
const r = (radius + padding) * Math.sqrt(i);
const a = i * angle;
const x = r * Math.cos(a) + width / 2;
const y = r * Math.sin(a) + height / 2;
if (x < -radius
|| y < -radius
|| x > width + radius
|| y > height + radius) continue;
const o = omega(i, P);
context.beginPath();
context.arc(x, y, radius / o, 0, 2 * Math.PI);
context.fill();
if (i % q === 0) yield context.canvas;
}
}
Insert cell
P = [...primes(n)]
Insert cell
height = Math.max(width, 720)
Insert cell
radius = 1.6
Insert cell
padding = 0.4
Insert cell
n = 120000
Insert cell
q = 200
Insert cell
angle = Math.PI * (3 - Math.sqrt(5))
Insert cell
function omega(x, P = [...primes(x)]) {
let o = 0;
for (const p of P) {
if (x % p === 0) {
++o;
x /= p;
}
if (p >= x) {
break;
}
}
return o;
}
Insert cell
function* primes(max) {
if (!(max >= 2)) return;

let j = 1;
let p = [2];
let mult = [];
let ord = 2;
let square = 9;

function isFactor(n) {
while (mult[n] < j) mult[n] += p[n] * 2;
return mult[n] === j;
}

function isPrime() {
let n = 0;
while (++n < ord) if (isFactor(n)) return false;
return true;
}

yield 2;
while (true) {
do {
j += 2;
if (j === square) {
mult[ord - 1] = j;
square = p[ord] ** 2;
++ord;
}
} while (!isPrime());
if (j > max) return;
p.push(j);
yield j;
}
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more