Public
Edited
Aug 22, 2023
Importers
2 stars
Also listed in…
Generative Art
Libraries
Insert cell
Insert cell
Insert cell
Insert cell
interactionCanvas = {
const noise = noise2(params);
const img = perlinImage(noise);
const { width, height } = img;
const canvas = DOM.canvas(width, height);
const ctx = canvas.getContext("2d");
let circle = mutable sampleCircle;
const refresh = () => {
ctx.clearRect(0, 0, width, height);
ctx.drawImage(img, 0, 0);
ctx.beginPath();
const n = 500;
const [x0, y0] = circle.center;
const r = circle.radius;
mutable sampleCircle = circle;
for (let i = 0; i < n; i++) {
const ang = (i / n) * Math.PI * 2;
const [cos, sin] = [Math.cos(ang), Math.sin(ang)];
const R = (noise(cos * r + x0, sin * r + y0) + 1) * r;
ctx.lineTo(x0 + cos * R, y0 + sin * R);
}
ctx.closePath();
ctx.lineWidth = 2;
ctx.strokeStyle = "orange";
ctx.stroke();
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
circle.draw(ctx);
};
refresh();
let mouse;
canvas.onmousedown = (e) => {
refresh();
mouse = [e.offsetX, e.offsetY];
if (vec2.dist(mouse, circle.center) < 4) {
canvas.onmousemove = (e) => {
let newmouse = [e.offsetX, e.offsetY];
circle.center = vec2.add(
[],
circle.center,
vec2.sub([], newmouse, mouse)
);
mouse = newmouse;
refresh();
};
} else if (vec2.dist(mouse, circle.borderPoint) < 4) {
canvas.onmousemove = (e) => {
let newmouse = [e.offsetX, e.offsetY];
circle.borderPoint = vec2.add(
[],
circle.borderPoint,
vec2.sub([], newmouse, mouse)
);
mouse = newmouse;
refresh();
};
}
};
canvas.onmouseup = () => {
canvas.onmousemove = null;
};
return canvas;
}
Insert cell
data
X
x
Y
y
Color
Size
Facet X
Facet Y
Mark
Auto
Type Chart, then Shift-Enter. Ctrl-space for more options.

Insert cell
mutable noiseloop = new NoiseLoop(
sampleCircle.center,
sampleCircle.radius,
noise2(params),
{ range: [-1, 1] }
)
Insert cell
data = d3.range(0, 1, 0.001).map((x) => ({ x, y: noiseloop.value(x) }))
Insert cell
function perlinImage(noise, options = {}) {
const { height = 400, width = 400 } = options;
const context = DOM.context2d(width, height, 1);
const image = context.createImageData(width, height);
for (let y = 0, i = 0; y < height; ++y) {
for (let x = 0; x < width; ++x, i += 4) {
image.data[i + 3] = (noise(x, y) + 0.5) * 256;
}
}
context.putImageData(image, 0, 0);
return context.canvas;
}
Insert cell
noise2 = function (options = {}) {
const { xScaleLog = -5, yScaleLog = -5, octaves = 3 } = options;
const xScale = 2 ** xScaleLog;
const yScale = 2 ** yScaleLog;
const noise = octave(perlin2, octaves);
return (x, y) => noise(x * xScale, y * yScale);
}
Insert cell
class NoiseLoop {
constructor(center, radius, noise, options = {}) {
const { domain = [0, 1], range = [0, 1] } = options;
Object.assign(this, { center, radius, noise, domain, range });
}
value(d) {
const angle =
((d - this.domain[0]) / (this.domain[1] - this.domain[0])) * Math.PI * 2;
const x = this.center[0] + this.radius * Math.cos(angle);
const y = this.center[1] + this.radius * Math.sin(angle);
return (
(this.noise(x, y) + 0.5) * (this.range[1] - this.range[0]) + this.range[0]
);
}
}
Insert cell
mutable sampleCircle = new Circle([200, 200], 50)
Insert cell
class Circle {
constructor(center, radius) {
this._center = [...center];
this._borderPoint = [center[0] + radius, center[1]];
}
set borderPoint(p) {
this._borderPoint = [...p];
}
get borderPoint() {
return [...this._borderPoint];
}
set center(p) {
let v = vec2.sub([], p, this._center);
this._center = [...p];
vec2.add(this._borderPoint, this._borderPoint, v);
}
get center() {
return [...this._center];
}
get radius() {
return vec2.dist(this._borderPoint, this._center);
}
draw(ctx, pointRadius = 4) {
ctx.beginPath();
ctx.arc(...this._center, this.radius, 0, Math.PI * 2);
ctx.stroke();
ctx.beginPath();
ctx.arc(...this._center, pointRadius, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.arc(...this._borderPoint, pointRadius, 0, Math.PI * 2);
ctx.fill();
}
}
Insert cell
import { perlin2, perlin3, octave } from "@mbostock/perlin-noise"
Insert cell
import { vec2 } from "@esperanc/vec2-utils"
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more