Published
Edited
Aug 23, 2021
Fork of Regl
Insert cell
Insert cell
canvas = DOM.canvas(width, 500)
Insert cell
regl.frame(() => {
camera(function () {
regl.clear({ color: [1, 1, 1, 1] });
drawPoints();
drawCurves({
texture: mkTexture(),
...payload
});
});
})
Insert cell
camera = (await require("https://bundle.run/regl-camera@2.1.1"))(regl, {
center: [0, 0, 0],
theta: Math.PI / 2.0,
phi: 0,
distance: 300,
damping: 0,
noScroll: true,
zoomSpeed: 2,
renderOnDirty: true,
mouse: true,
})
Insert cell
drawPoints = {
const position = data.flatMap(x => [x.p1, x.p2]);
return regl({
vert: `
precision mediump float;
uniform mat4 projection, view;
attribute vec2 position;
void main () {
gl_PointSize = 4.0;
gl_Position = projection * view * vec4(position, 0.0, 1.0);
}`,
frag: `
precision mediump float;
void main () {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}`,
attributes: {
position,
},
count: position.length,
primitive: 'points',
})
}
Insert cell
payload = {
const position = []
const elements = []
const colorIndex = []

for (const [index, { path }] of data.entries()) {
const offset = position.length
position.push(...path)

const range = d3.range(offset, offset + path.length)
const [, ...tail] = range
elements.push(...d3.zip(range, tail).flat(1))

colorIndex.push(...Array.from({ length: path.length }).fill(index / data.length).flatMap(x => [x, x]))
}

console.log(position.length, colorIndex.length, elements.length)

return {
position: regl.buffer(position),
colorIndex: regl.buffer(colorIndex),
elements: regl.elements({
primitive: 'lines',
count: elements.length,
data: elements
}),
}
}
Insert cell
drawCurves = regl({
vert: `
precision mediump float;

uniform mat4 projection, view;
attribute vec2 position;

attribute vec2 colorIndex;
varying vec2 uv;

void main () {
uv = colorIndex;
gl_Position = projection * view * vec4(position, 0.0, 1.0);
}`,
frag: `
precision mediump float;

uniform sampler2D texture;

varying vec2 uv;

void main () {
gl_FragColor = vec4(uv.x, uv.y, 0.0, 1.0);
gl_FragColor = texture2D(texture, uv);
}`,

attributes: {
position: regl.prop('position'),
colorIndex: regl.prop('colorIndex'),
},

uniforms: {
texture: regl.prop('texture')
},

elements: regl.prop('elements')
})

Insert cell
mkTexture = function() {
return regl.texture({
width: 32,
height: 32,
format: 'rgba',
type: 'uint8',
data: d3.range(0, 32*32).map((_, id) => {
const { r, g, b } = d3.color(d3.interpolateWarm(d3.randomInt(32*32)() / (32 * 32)));
return [r, g, b, 255];
}),
})
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
numPoints = 100_000
Insert cell
data = Array.from({ length: numPoints }).map(() => {
const p1 = [rnd(), rnd()]
const p2 = [rnd(), rnd()]

const cp1 = [rnd(), rnd()]
const cp2 = [rnd(), rnd()]
const precision = d3.randomUniform(0.0001, 0.1)();

const path = [p1];
for (let t = precision; t < 1 - precision / 2; t += precision) {
const x = (1 - t) ** 3 * p1[0] +
3 * (1 - t) ** 2 * t * cp1[0] +
3 * (1 - t) * t ** 2 * cp2[0] +
t ** 3 * p2[0];

const y = (1 - t) ** 3 * p1[1] +
3 * (1 - t) ** 2 * t * cp1[1] +
3 * (1 - t) * t ** 2 * cp2[1] +
t ** 3 * p2[1];

path.push([x, y]);
}

path.push(p2);
return { p1, p2, path }
})
Insert cell
range = [-numPoints / 1000, numPoints / 1000]
Insert cell
rnd = d3.randomUniform(...range)
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