Published
Edited
Mar 11, 2021
1 fork
7 stars
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
n_points = Math.floor(Math.exp(n_points_log))
Insert cell
md`# WebGL implementation.

This implementation is a little ad-hoc; I just hard code in that there will be 17 loops, because 3**17 seems like more points than anyone could reasonably lay out.

Although this particular code assumed that all blocks are the same size, a language that facilitates indexing arrays can have different baskets of sizes.

`
Insert cell
3**17
Insert cell
grid2 = glsl`


/*
Here is a GLSL function that calculates MOD accurately with (float) parameters that should be integers:
*/
// https://stackoverflow.com/questions/33908644/get-accurate-integer-modulo-in-webgl-shader

float modI(float a,float b) {
float m=a-floor((a+0.5)/b)*b;
return floor(m+0.5);
}

float reposition(float ix, float i, float base, float flip_this, inout float flip_other) {
// FML floating point numbers... is why I need 0.5 here. Sometimes it won't be high enough.
float rank_in_layer = floor((ix + .5) / (pow(base, i)));
if (rank_in_layer == 0.) {return 0.;}
float position_on_axis = floor(i / 2.);
float position = modI(rank_in_layer, base);
float width_of_each = pow(base + u_separation, position_on_axis);
if (flip_this == -1.) {
position = base - position - 1.;
}
if (u_boust == 1. && modI(position, 2.) == 1.) {
flip_other *= -1.;
}
return position * width_of_each;
}
vec2 grid2(float ix, float max_ix) {
float x = 0.;
float y = 0.;
float flip_y = 1.;
float flip_x = 1.;
for (float i = 17.0; i >= 0.; i -= 1.) {
if (modI(i, 2.) == 1.) {
x += reposition(ix, i, u_base, flip_y, flip_x);
} else {
y += reposition(ix, i, u_base, flip_x, flip_y);
}
}
vec2 xy = vec2(x, y) / sqrt(max_ix) / 3.4;
return positioner(xy) * vec2(1., -1.);
}
`
Insert cell
vertex_shader = glsl`
precision highp float;

attribute float ix;

uniform float u_time;
uniform float u_boust;
uniform float u_max_ix;
uniform float tick;
uniform sampler2D u_color_buffer;
uniform float u_separation;
uniform float u_base;
varying vec4 fill;

vec2 positioner(vec2 fracts) {
return 1.95 * vec2(fracts.x - .5, fracts.y - .5);
}

${grid2.value}

void main() {
vec2 pos = grid2(ix, u_max_ix);
gl_Position = vec4(pos.x, pos.y, 0., 1.);
gl_PointSize = 2.;

float prop_through = ix / u_max_ix;
float offset = -fract(u_time / 5.);
fill = texture2D(u_color_buffer, vec2(fract(offset + ix/u_max_ix), 0.5));
}
`
Insert cell
aspect_ratio = 1
Insert cell
3 * 5 * 5 * 5
Insert cell
{
const numbers = []
const fives = 0;
const threes = 0;
const sevens = 0;
for (let i of d3.range(10)) {
const i_ = 3 ** i
for (let j of d3.range(8)) {
const j_ = 5 ** j
for (let k of d3.range(6)) {
const k_ = 7 ** k
numbers.push([i_ * j_ * k_, [i, j, k]])
}
}
}
numbers.sort((a, b) => a[0] - b[0])
return numbers
}
Insert cell
{
const tick = regl.frame(({time}) => {
// clear contents of the drawing buffer
regl.clear({
color: [0, 0, 0, 0],
depth: 1
})
drawPoints({})
// draw a triangle using the command defined above
})
invalidation.then(() => tick.cancel())
}
Insert cell
fragment_shader = glsl`
precision mediump float;
varying vec4 fill;

void main() {
gl_FragColor = fill;
}
`
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
drawPoints = {
const regl_params = {
depth: { enable: false },
stencil: { enable: false },
blend: {
enable: true,
func: {
srcRGB: 'one',
srcAlpha: 'one',
dstRGB: 'one minus src alpha',
dstAlpha: 'one minus src alpha',
},
},
frag: fragment_shader.value,
vert: vertex_shader.value,
attributes: {
ix: {
buffer: points,
stride: 4,
offset: 0
},
},
uniforms: {
tick: ({ tick }) => tick,
u_max_ix: n_points,
u_boust: order == "Boustrephedon" ? 1 : 0,
u_time: regl.context("time"),
u_aspect_ratio: aspect_ratio,
u_color_buffer: colorscheme,
u_separation: padding,
u_base: ordinality,
},
// specify the number of points to draw
count: n_points - 1,

// specify that each vertex is a point (not part of a mesh)
primitive
}

return regl(regl_params)
}
Insert cell
md`# Create a colorscheme`
Insert cell
load_time = Date.now()
Insert cell
points = regl.buffer(vals)
Insert cell
vals = {
return d3.range(0, 8000000)
}
Insert cell
colorscheme = regl.texture(canvas)
Insert cell
wrapREGL = require('regl')
Insert cell
import { glsl } from "@stwind/glsl-chunk-tag";
Insert cell
d3 = require("d3@v6")
Insert cell
import {Button, Checkbox, Toggle, Radio, Range, Select, Text, Textarea, Search, Table} from "@observablehq/inputs"

Insert cell
import { set } from "@observablehq/synchronized-inputs"
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