Published
Edited
May 22, 2022
4 forks
2 stars
Insert cell
Insert cell
{
// The drawing canvas
const canvas = html`<canvas width=500 height=500 style="border:1px solid gray" />`;
yield canvas;

// The regl objects
let { regl, drawCircle } = circleRenderProgram(canvas);

// Click callback (pause)
let run = true;
canvas.onmousedown = () => {
run = !run;
};

// A set of lights
let circles = [new circleLight()];
const maxCircles = 30;
const minCircles = 5;
const createProbability = 0.01;

// The animation
for (let frame = 0; ; frame++) {
if (run) {
regl.clear({
color: [0, 0, 0, 1]
});
for (let circle of circles) {
drawCircle(circle);
circle.animate();
}
circles = circles.filter((c) => !c.terminated);
if (
circles.length < maxCircles &&
(circles.length < minCircles || Math.random() < createProbability)
)
circles.push(new circleLight());
}
yield canvas;
}
}
Insert cell
palette = d3.schemeAccent.map((c) => {
let color = d3.color(c);
return [color.r / 255, color.g / 255, color.b / 255, 1];
})
Insert cell
class circleLight {
constructor(aspect = 1) {
this.pos = [(Math.random() * 2 - 1) * aspect, Math.random() * 2 - 1];
this.r = 0.01;
this.maxR = Math.random() * 0.8 + 0.2;
this.color = palette[~~(Math.random() * palette.length)];
this.increment = 0.001;
}
get terminated() {
return this.r < 0;
}
animate() {
if (!this.terminated) {
this.r += this.increment;
}
if (this.r > this.maxR) this.increment = -this.increment;
}
}
Insert cell
function circleRenderProgram(canvas) {
const regl = createRegl(canvas);

const drawCircle = regl({
frag: `
precision mediump float;
uniform vec4 color;
uniform vec2 pos;
uniform float r;
uniform vec2 resolution;


float sdCircle ( in vec2 p, in vec2 pos, in float r )
{
return length (p-pos) - r;
}

void main () {
vec2 p = (2.0*gl_FragCoord.xy-resolution)/resolution.y;
float d = sdCircle(p, pos, r);
if (d >= 0. && d <= 1.) {
float t = smoothstep(0.,0.005,d)-smoothstep(0.005,0.01,d);
gl_FragColor = vec4(color.xyz,(t+0.8*pow((1.-d),5.))*smoothstep(0.,0.1,r));
}
else discard;
}`,

vert: `
attribute vec2 position;
void main () {
gl_Position = vec4(position, 0., 1.);
}`,

attributes: {
position: [
[-1, -1],
[1, -1],
[1, 1],
[-1, 1]
]
},

depth: {
enable: false
},

primitive: "triangle fan",

blend: {
enable: true,
func: {
srcRGB: "src alpha",
srcAlpha: 1,
dstRGB: "one minus src alpha",
dstAlpha: 1
}
},

count: 4,

uniforms: {
resolution: [canvas.width, canvas.height],
r: regl.prop("r"),
pos: regl.prop("pos"),
color: regl.prop("color")
}
});

return { regl, drawCircle };
}
Insert cell
Insert cell
Insert cell
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