Published
Edited
Nov 3, 2020
5 forks
34 stars
Insert cell
Insert cell
canvas = DOM.canvas(width, height)
Insert cell
{
gl.useProgram(program);
gl.enableVertexAttribArray(a_corner);
gl.vertexAttribPointer(a_corner, 2, gl.FLOAT, false, 0, 0);
while (true) {
let now = Date.now();
gl.uniform2f(
u_ball1,
(Math.sin(now / 3700) / 4 + 0.5) * width,
(Math.cos(now / 3700) / 3 + 0.5) * height
);
gl.uniform2f(
u_ball2,
(-Math.sin(now / 900) / 3 + 0.5) * width,
(Math.cos(now / 900) / 5 + 0.5) * height
);
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
yield now;
}
}
Insert cell
fragmentShader = {
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, `
precision highp float;
uniform vec2 u_ball1;
uniform vec2 u_ball2;

const float PI = 3.14159265359;

// https://github.com/d3/d3-color
vec3 cubehelix(vec3 c) {
float a = c.y * c.z * (1.0 - c.z);
float cosh = cos(c.x + PI / 2.0);
float sinh = sin(c.x + PI / 2.0);
return vec3(
(c.z + a * (1.78277 * sinh - 0.14861 * cosh)),
(c.z - a * (0.29227 * cosh + 0.90649 * sinh)),
(c.z + a * (1.97294 * cosh))
);
}

// https://github.com/d3/d3-scale-chromatic
vec3 cubehelixDefault(float t) {
return cubehelix(vec3(mix(300.0 / 180.0 * PI, -240.0 / 180.0 * PI, t), 0.5, t));
}

void main(void) {
float f = 1.0 / distance(gl_FragCoord.xy, u_ball1) + 1.0 / distance(gl_FragCoord.xy, u_ball2);
float t = smoothstep(0.0, 1.0, (0.04 - f) / 0.04);
gl_FragColor = vec4(cubehelixDefault(t), 1.0);
}
`);
gl.compileShader(shader);
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader;
throw new Error(gl.getShaderInfoLog(shader));
}
Insert cell
vertexShader = {
const shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(shader, `
attribute vec2 a_corner;
void main(void) {
gl_Position = vec4(a_corner, 0.0, 1.0);
}
`);
gl.compileShader(shader);
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader;
throw new Error(gl.getShaderInfoLog(shader));
}
Insert cell
program = {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (gl.getProgramParameter(program, gl.LINK_STATUS)) return program;
throw new Error(gl.getProgramInfoLog(program));
}
Insert cell
cornerBuffer = {
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, Float32Array.of(-1, -1, +1, -1, +1, +1, -1, +1), gl.STATIC_DRAW);
return buffer;
}
Insert cell
a_corner = gl.getAttribLocation(program, "a_corner")
Insert cell
u_ball1 = gl.getUniformLocation(program, "u_ball1")
Insert cell
u_ball2 = gl.getUniformLocation(program, "u_ball2")
Insert cell
gl = canvas.getContext("webgl", {depth: false})
Insert cell
height = 600
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