Public
Edited
Jan 18, 2023
1 fork
2 stars
Insert cell
Insert cell
Insert cell
plot1.canvas
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
paused = {
button;
return !this;
}
Insert cell
paused &&
(() => {
now;
if (timer.elapsed() > 20) {
timer.update();
// console.log(mX, mY, mousePos.x, mousePos.y);
plot1.regl.clear({ color: [0.7, 0.8, 0.8, 1] });
cmdTextureColor(plot1, cmd)(mousePos);
}
console.log("a");
})()
Insert cell
draw1 = {
plot1.regl.clear({ color: [0.7, 0.8, 0.8, 1] });
cmdTextureColor(plot1, cmd)(mousePos);
return 'Alpha: Hue; Beta: Size; Theta: Ratio between Texture and Vertex Rendering';
}
Insert cell
plot1 = createPlot()
Insert cell
Insert cell
mousemove = {
const callback = (mX, mY) => {
// const { offsetX, offsetY } = event;
const { width, height } = layout;
const { x, y } = mousePos;
mousePos.x = (mX * 2 - width) / width;
mousePos.y = -(mY * 2 - height) / height;

if (timer.elapsed() > 20) {
timer.update();
// console.log(mX, mY, mousePos.x, mousePos.y);
plot1.regl.clear({ color: [0.7, 0.8, 0.8, 1] });
cmdTextureColor(plot1, cmd)(mousePos);
}
};

console.log(plot1.regl.context('pixelRatio'));

d3.select(plot1.canvas).on('mousemove', mouseEvent => {
const { offsetX, offsetY } = mouseEvent;
callback(offsetX, offsetY);
});

d3.select(plot1.canvas).on('touchmove', touchEvent => {
console.log(touchEvent);
touchEvent.preventDefault();
const { x, y } = plot1.canvas.getBoundingClientRect();
const offsetX = touchEvent['touches'][0].clientX - x;
const offsetY = touchEvent['touches'][0].clientY - y;
callback(offsetX, offsetY);
});
}
Insert cell
Insert cell
function createPlot(opts) {
const { width, height, pixelRatio, aspectRatio } = layout;

let canvas = DOM.canvas(width * pixelRatio, height * pixelRatio);

canvas.style.width = width + 'px';
canvas.style.height = height + 'px';

let regl = wrapREGL({
canvas: canvas,
pixelRatio: pixelRatio,
extensions: ['oes_standard_derivatives']
});

return { canvas, regl };
}
Insert cell
cmdTextureColor = (plot, cmdF) =>
plot.regl({
vert: `
${glsl.useStandardDerivatives}
${glsl.constants}
${glsl.precision}
${glsl.hsv2rgb}
attribute vec2 position;
varying vec3 fcolor;
varying vec2 fpos;
uniform float offset;

void main() {
fpos = position;
fcolor = hsv2rgb(vec3(atan(position[1], position[0])*HALF_PI_INV + offset,1.0,1.0));
gl_Position = vec4(position, 0.0, 1.0);
}
`,

frag: `
${glsl.useStandardDerivatives}
${glsl.constants}
${glsl.precision}
${glsl.hypot}
${glsl.complex}
${glsl.wireframe}
${glsl.hsv2rgb}

varying vec2 fpos;
varying vec3 fcolor;

uniform float eps;
// uniform float pn;
uniform float offset;
uniform vec2 zRange;
uniform vec2 mousePos;
uniform float pixelRatio;
uniform float rectGridSpace;

// ${cmdF}
// vec2 f (vec2 z) {
// vec2 a = vec2(1.2, 0.7);
// return cpow(z - a, pn);
// }

void main() {
vec2 fz = f(fpos * zRange);
vec2 mouseZ = mousePos * zRange;

float HSVValue = mix(0.6, 0.9, min(1.0, length(fz)/zRange[0]));
float HSVSat = mix(1.0, 0.5, min(1.0, length(fz)/zRange[0]));
vec3 hueColor = hsv2rgb(vec3(atan(fz[1], fz[0]) * HALF_PI_INV + offset, HSVSat, HSVValue));

float gridFactor = 0.0;

vec2 grids = vec2(rectGridSpace);
gridFactor = 0.8 - wireframe(fz/grids, pixelRatio * 0.5, 4.0);

if (abs(distance(fz, mouseZ) - 1.0) < eps) {
gridFactor = 1.0;
}

gl_FragColor = mix(
vec4(hueColor, 1.0),
vec4(vec3(1.0), 1.0),
gridFactor
);
}
`,

attributes: {
position: [
// Triangle S
[1.0, -1.0], // ES
[0.0, 0.0], // CC
[-1.0, -1.0], // WS

// Triangle N
[0.0, 0.0], // CC
[1.0, 1.0], // EN
[-1.0, 1.0], // WN

// Triangle W
[0.0, 0.0], // CC
[-1.0, 1.0], // WN
[-1.0, -1.0], // WS

// Triangle E
[0.0, 0.0], // CC
[1.0, -1.0], // ES
[1.0, 1.0] // EN
]
},

uniforms: {
offset: offsetHue,
// pn: pn,
zRange: [scaleX, scaleX * aspectRatio],
mousePos: [plot.regl.prop('x'), plot.regl.prop('y')],
eps: (scaleX / layout.width) * 2,
rectGridSpace: rectGridSpace,
pixelRatio: plot.regl.context('pixelRatio'),
num1: [cps[0].move()[0], cps[0].y],
num2: [cps[1].move()[0], cps[1].y],
num3: [cps[2].move()[0], cps[2].y],
num4: [cps[3].move()[0], cps[3].y],
pn1: cps[0].pn,
pn2: cps[1].pn,
pn3: cps[2].pn,
pn4: cps[3].pn
},

count: 3 * 4
})
Insert cell
glsl = ({
useStandardDerivatives: `
#extension GL_OES_standard_derivatives : enable
`,
constants: `
#define PI 3.141592653589793238
#define HALF_PI 1.57079632679
#define HALF_PI_INV 0.15915494309
#define LOG_2 0.69314718056
#define C_ONE (vec2(1.0, 0.0))
#define C_I (vec2(0.0, 1.0))
#define TO_RADIANS 0.01745329251
`,
precision: `
precision highp float;
`,
hsv2rgb: `
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
`,
complex: `
float cosh (float x) {
return 0.5 * (exp(x) + exp(-x));
}

float sinh (float x) {
return 0.5 * (exp(x) - exp(-x));
}

vec2 sinhcosh (float x) {
float ex = exp(x);
float emx = exp(-x);
return 0.5 * vec2(
ex + emx,
ex - emx
);
}

vec2 cmul (vec2 a, vec2 b) {
return vec2(
a.x * b.x - a.y * b.y,
a.y * b.x + a.x * b.y
);
}

vec2 cmul (vec2 a, vec2 b, vec2 c) {
return cmul(cmul(a, b), c);
}

vec2 cdiv (vec2 a, vec2 b) {
return vec2(
a.y * b.y + a.x * b.x,
a.y * b.x - a.x * b.y
) / dot(b, b);
}

vec2 cinv (vec2 z) {
return vec2(z.x, -z.y) / dot(z, z);
}

vec2 cexp (vec2 z) {
return vec2(cos(z.y), sin(z.y)) * exp(z.x);
}

vec2 clog (vec2 z) {
return vec2(
log(hypot(z)),
atan(z.y, z.x)
);
}

vec2 cpolar (vec2 z) {
return vec2(
atan(z.y, z.x),
hypot(z)
);
}

vec2 cpow (vec2 z, float x) {
float r = hypot(z);
float theta = atan(z.y, z.x) * x;
return vec2(cos(theta), sin(theta)) * pow(r, x);
}

vec2 cpow (vec2 a, vec2 b) {
float aarg = atan(a.y, a.x);
float amod = hypot(a);
float theta = log(amod) * b.y + aarg * b.x;
return vec2(cos(theta), sin(theta)) * pow(amod, b.x) * exp(-aarg * b.y);
}

vec2 csqrt (vec2 z) {
vec2 zpolar = cpolar(z);
float theta = zpolar.x * 0.5;
float mod = sqrt(zpolar.y);
return vec2(cos(theta), sin(theta)) * mod;
}

vec2 csqr (vec2 z) {
return vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y);
}

vec2 ccos (vec2 z) {
return sinhcosh(z.y) * vec2(cos(z.x), -sin(z.x));
}

vec2 csin (vec2 z) {
return sinhcosh(z.y).yx * vec2(sin(z.x), cos(z.x));
}

vec2 ctan (vec2 z) {
vec2 e2iz = cexp(2.0 * vec2(-z.y, z.x));
return cdiv(e2iz - C_ONE, cmul(C_I, C_ONE + e2iz));
}

vec2 cacos (vec2 z) {
vec2 t1 = csqrt(vec2(z.y * z.y - z.x * z.x + 1.0, -2.0 * z.x * z.y));
vec2 t2 = clog(vec2(t1.x - z.y, t1.y + z.x));
return vec2(HALF_PI - t2.y, t2.x);
}

vec2 casin (vec2 z) {
vec2 t1 = csqrt(vec2(z.y * z.y - z.x * z.x + 1.0, -2.0 * z.x * z.y));
vec2 t2 = clog(vec2(t1.x - z.y, t1.y + z.x));
return vec2(t2.y, -t2.x);
}
vec2 catan (vec2 z) {
float d = z.x * z.x + (1.0 - z.y) * (1.0 - z.y);
vec2 t1 = clog(vec2(1.0 - z.y * z.y - z.x * z.x, -2.0 * z.x) / d);
return 0.5 * vec2(-t1.y, t1.x);
}

vec2 ccosh (vec2 z) {
return sinhcosh(z.x).yx * vec2(cos(z.y), sin(z.y));
}

vec2 csinh (vec2 z) {
return sinhcosh(z.x) * vec2(cos(z.y), sin(z.y));
}

vec2 ctanh (vec2 z) {
vec2 ez = cexp(z);
vec2 emz = cexp(-z);
return cdiv(ez - emz, ez + emz);
}
`,
hypot: `
float hypot (vec2 z) {
float t;
float x = abs(z.x);
float y = abs(z.y);
t = min(x, y);
x = max(x, y);
t = t / x;
return x * sqrt(1.0 + t * t);
}
`,
wireframe: `
// https://github.com/rreusser/glsl-solid-wireframe
float wireframe (float parameter, float width, float feather) {
float w1 = width - feather * 0.5;
float d = fwidth(parameter);
float looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
return smoothstep(d * w1, d * (w1 + feather), looped);
}

float wireframe (vec2 parameter, float width, float feather) {
float w1 = width - feather * 0.5;
vec2 d = fwidth(parameter);
vec2 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec2 a2 = smoothstep(d * w1, d * (w1 + feather), looped);
return min(a2.x, a2.y);
}

float wireframe (vec3 parameter, float width, float feather) {
float w1 = width - feather * 0.5;
vec3 d = fwidth(parameter);
vec3 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec3 a3 = smoothstep(d * w1, d * (w1 + feather), looped);
return min(min(a3.x, a3.y), a3.z);
}

float wireframe (vec4 parameter, float width, float feather) {
float w1 = width - feather * 0.5;
vec4 d = fwidth(parameter);
vec4 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec4 a4 = smoothstep(d * w1, d * (w1 + feather), looped);
return min(min(min(a4.x, a4.y), a4.z), a4.w);
}

float wireframe (float parameter, float width) {
float d = fwidth(parameter);
float looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
return smoothstep(d * (width - 0.5), d * (width + 0.5), looped);
}

float wireframe (vec2 parameter, float width) {
vec2 d = fwidth(parameter);
vec2 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec2 a2 = smoothstep(d * (width - 0.5), d * (width + 0.5), looped);
return min(a2.x, a2.y);
}

float wireframe (vec3 parameter, float width) {
vec3 d = fwidth(parameter);
vec3 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec3 a3 = smoothstep(d * (width - 0.5), d * (width + 0.5), looped);
return min(min(a3.x, a3.y), a3.z);
}

float wireframe (vec4 parameter, float width) {
vec4 d = fwidth(parameter);
vec4 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec4 a4 = smoothstep(d * (width - 0.5), d * (width + 0.5), looped);
return min(min(min(a4.x, a4.y), a4.z), a4.z);
}
`
})
Insert cell
cmdF = () => {
const s = `
uniform vec2 num1;
uniform vec2 num2;
uniform vec2 num3;
uniform vec2 num4;
uniform float pn1;
uniform float pn2;
uniform float pn3;
uniform float pn4;
vec2 f (vec2 z) {
vec2 fz = C_ONE;
fz = cmul(fz, csqr(z - num1));
fz = cmul(fz, csqr(z) - num2);
fz = cdiv(fz, csqr(z) - num3);
fz = cmul(fz, csqr(z - num4));
return fz;
}
`;
return s;
}
Insert cell
cps = generateCP()
Insert cell
generateCP = (n = 5) => {
const cps = [];
for (let i = 0; i < n; i++) {
cps.push(
new ComplexPoint(
0,
0,
rnd() * scaleSpeed,
rnd() * scaleSpeed,
[-scaleX, scaleX, -scaleX, scaleX, 1, 2],
(-1) ** i * (1 + rnd()),
rnd() * 0.01
)
);
}
return cps;
}
Insert cell
class ComplexPoint {
constructor(x, y, vx, vy, lrtbnm, pn, vn) {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
this.lrtbnm = lrtbnm;
this.pn = pn;
this.vn = vn;
}

get xyn() {
return [this.x, this.y, this.pn];
}

move() {
this.x += this.vx;
this.y += this.vy;
this.pn += this.vn;

if (this.x < this.lrtbnm[0] || this.x > this.lrtbnm[1]) {
this.vx *= -1;
this.x += 2 * this.vx;
}

if (this.y < this.lrtbnm[2] || this.y > this.lrtbnm[3]) {
this.vy *= -1;
this.y += 2 * this.vy;
}

if (this.pn < this.lrtbnm[4] || this.pn > this.lrtbnm[5]) {
this.vn *= -1;
this.pn += 2 * this.vn;
}

return this.xyn;
}
}
Insert cell
rnd = (scale = 1.0) => scale * Math.random()
Insert cell
Insert cell
Insert cell
layout = Object.assign({
aspectRatio: aspectRatio,
width: window.innerWidth * 0.9,
height: window.innerWidth * 0.9 * aspectRatio,
pixelRatio: 2
})
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