Public
Edited
Apr 5
Insert cell
Insert cell
Insert cell
Insert cell
canvas = {
const div = document.createElement("div");
div.className = 'container'
const layer1 = DOM.context2d(w, w);
const layer2 = DOM.context2d(w, w);

const colors = d3.schemeSpectral[10];
div.append(layer1.canvas, layer2.canvas);
layer1.canvas.style.background = "hsl(216deg 20% 8%)";
layer2.textBaseline = 'ideographic'
layer2.textAlign = 'center'
layer2.font = `${radius}px serif`;

const headerDotSize = 40 / nOscillators;
const freqs = d3.range(1, nOscillators + 1).map(patternF)
const speed = -1e-2;
// Store last oscillator x,y
const prevPositions = {}

// Draw top row of circles with oscillators

let counter = 0;
while (true) {

counter += 1;
// context.clearRect(0,0,width, height);
layer2.fillStyle = "hsl(216deg 0% 83%)";
layer2.strokeStyle = "hsl(216deg 0% 83%)";

// Draw our Grid
layer2.clearRect(0, 0, w, w);
freqs.forEach((freq, i) => {
layer2.globalAlpha = 1;
const offset = (gap + radius * 2) * (i + 1) + gap;
const position = radius + Math.sin(counter * speed * freq) * radius;
const compliment = radius + Math.cos(counter * speed * freq) * radius;
// X Header
layer2.beginPath();
layer2.arc(offset + radius, gap + radius, radius, 0, Math.PI * 2);
layer2.stroke();

// Number
layer2.beginPath();
layer2.fillText(freq, offset + radius, gap + radius * 1.5)
// Draw a circle at the position of the oscillator
layer2.beginPath();
layer2.arc(offset + position, gap + compliment, headerDotSize, 0, Math.PI * 2);
layer2.fill();

// Y Header
layer2.beginPath();
layer2.arc(gap + radius, offset + radius, radius, 0, Math.PI * 2);
layer2.stroke();

// Number
layer2.beginPath();
layer2.fillText(freq, gap + radius, offset + radius * 1.5)

// Draw a circle at the position of the oscillator
layer2.beginPath();
layer2.arc(
gap + position,
offset + compliment,
headerDotSize, 0, Math.PI * 2);
layer2.fill();

layer2.globalAlpha = 0.4;
// LineX
layer2.beginPath();
layer2.moveTo(offset + position, 0)
layer2.lineTo(offset + position, w)
layer2.stroke();
// LineY
layer2.beginPath();
layer2.moveTo(0, offset + compliment)
layer2.lineTo(w, offset + compliment)
layer2.stroke();
})

// draw our paint
freqs.forEach((freqX, i) => {
freqs.forEach((freqY, j) => {
// Pick a color
layer1.strokeStyle = colors[(i + j) % 10];
layer1.globalAlpha = 1
const offsetX = (gap + radius * 2) * (i + 1) + gap;
const offsetY = (gap + radius * 2) * (j + 1) + gap;
const position = radius + Math.sin(counter * speed * freqX) * radius;
const compliment = radius + Math.cos(counter * speed * freqY) * radius;

const [x, y] = [offsetX + position, offsetY + compliment];
const [prevX, prevY] = prevPositions[`${i},${j}`] ? prevPositions[`${i},${j}`] : [x,y];
// Our point (LAYER 1
layer1.beginPath();
layer1.moveTo(prevX, prevY);
layer1.lineTo(x, y);
layer1.stroke();
prevPositions[`${i},${j}`] = [x , y];
})
})
// Fade the canvas a bit
// layer1.globalAlpha = 0.01
// layer1.fillRect(0, 0, w, w)
yield div;
}
}
Insert cell
radius = (width - gap * (nOscillators + 1) - gap) / (nOscillators + 1) / 2

Insert cell
function patternF(n) {
if (pattern === 'sequential') return n;
if (pattern === 'fibonacci') return fib(n);
if (pattern === 'primes') return prime(n);
}
Insert cell
function prime(n) {
let count = 0;
let num = 2;
while (count < n) {
if (isPrime(num)) {
count++;
}
num++;
}
return num - 1;
}
Insert cell
function isPrime(num) {
if (num <= 1) {
return false;
}
for (let i = 2; i <= Math.sqrt(num); i++) {
if (num % i === 0) {
return false;
}
}
return true;
}
Insert cell
function fib(n) {
var result = 0;
if (n <= 2) {
return 1;
}
result = fib(n - 1) + fib(n - 2);
return result;
};

Insert cell
gap = 10;
Insert cell
w = width
Insert cell
html`
<style type="text/css">

.container {
position: relative;
height: ${w}px;
width: ${w}px;
}

.container canvas {
position: absolute;
top: 0;
left: 0;
}

</style>
`
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