Published
Edited
Jun 1, 2021
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
contourSpacing = 10000
// eh, we don't need those other contours! x' = 0 and y' = 0 together are enough.
Insert cell
padding = 20 // BRITTLE
// correct GLSL coordinates for plotter axes.
Insert cell
// logistic growth with variation over time
// t*3. * (50. - x) / 50. * x - 2. * (20. - y)/20. * y
Insert cell
Insert cell
Insert cell
draw = {
gl.useProgram(program);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.enableVertexAttribArray(a_vertex);
gl.vertexAttribPointer(a_vertex, 2, gl.FLOAT, false, 0, 0);
// while (true) {
// let t = (now / 3000) % 1;
let t = 1;

gl.uniform1f(gl.getUniformLocation(program, "t"), t);
gl.uniform1f(
gl.getUniformLocation(program, "contourSpacing"),
contourSpacing
);
gl.uniform1f(gl.getUniformLocation(program, "scale"), scale); // scale / 32.0 / 32.0
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
yield t;
// }
}
Insert cell
gl = {
const gl = buffer.getContext("webgl", { depth: false });
gl.getExtension('oes_standard_derivatives');
return gl;
}
Insert cell
fragmentShader = {
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(
shader,
`
#extension GL_OES_standard_derivatives : enable
precision highp float;

// const float pi = 3.14159265359;
const float width = ${canvas.width.toFixed(1)};
const float height = ${canvas.height.toFixed(1)};

const vec2 center = vec2(${padding - bottomLeft.x / scale}, ${padding -
bottomLeft.y / scale}); // vec2(width, height) / 2.0;
uniform float t, contourSpacing, scale;

float value(float x, float y) {
return (${value});
}
float value_(float x, float y) {
return (${value_});
}

float contourFunction (float f, float width, float feather) {
float w1 = width - feather * 0.5;
// Two slightly different options for the gradient magnitude. The first is a
// little faster, the second is a little more accurate. We use this to compute
// the required line width
//float d = fwidth(f);
float d = length(vec2(dFdx(f), dFdy(f)));

// Repeat the contour level every 1.0 units:
f = 0.5 - abs(mod(f, 1.0) - 0.5);

return smoothstep(d * w1, d * (w1 + feather), f);
}

void main(void) {
vec2 z = (gl_FragCoord.xy - center) * scale;
float f = value(z.x, z.y);
float contour = contourFunction(f / contourSpacing, 0.5, 0.75);

float f_ = value_(z.x, z.y);
float contour_ = contourFunction(f_ / contourSpacing, 0.5, 0.75);
gl_FragColor = vec4(vec3(contour * contour_), 1.0);
}
`
);
gl.compileShader(shader);
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader;
throw new Error(gl.getShaderInfoLog(shader));
}
Insert cell
Insert cell
vertexShader = {
const shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(shader, `
attribute vec2 a_vertex;
void main(void) {
gl_Position = vec4(a_vertex, 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
vertexBuffer = {
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_vertex = gl.getAttribLocation(program, "a_vertex")
Insert cell
height = 800
Insert cell
encode = f =>
encodeURIComponent(f)
.replace(/\(/g, "%28")
.replace(/\)/g, "%29")
Insert cell
Insert cell
Insert cell
Insert cell
orbitPlot = {
let plot = plotter({
xDomain: [
bottomLeft.x,
(canvas.width - 2 * padding) * scale + bottomLeft.x
],
yDomain: [
(canvas.height - 2 * padding) * scale + bottomLeft.y,
bottomLeft.y
],
width: canvas.width,
height: canvas.height
});
plot.polyline(orbit.map(([x, y]) => ({ x: x, y: y })));
let spiral = plot.node;

var svgURL = new XMLSerializer().serializeToString(spiral);
let img = new Image();
img.src = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgURL);

return img;
}
Insert cell
buffer = {
const canvas = DOM.canvas(
(width + 28) * devicePixelRatio,
height * devicePixelRatio
);
return canvas;
}
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