Published
Edited
Apr 2, 2020
1 fork
6 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
theta = {
let res = 0;
while (true) {
await Promises.delay(10);
res += 0.005;
yield res;
}
}
Insert cell
rotateXW = {
const m = new THREE.Matrix4();
return theta =>
// prettier-ignore
m.set(
Math.cos(theta), 0, 0, -Math.sin(theta),
0, 1, 0, 0,
0, 0, 1, 0,
Math.sin(theta), 0, 0, Math.cos(theta)
);
}
Insert cell
rotateYW = {
const m = new THREE.Matrix4();
return theta =>
// prettier-ignore
m.set(
1, 0, 0, 0,
0, Math.cos(theta), 0, -Math.sin(theta),
0, 0, 1, 0,
0, Math.sin(theta), 0, Math.cos(theta)
);
}
Insert cell
rotateZW = {
const m = new THREE.Matrix4();
return theta =>
// prettier-ignore
m.set(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, Math.cos(theta), -Math.sin(theta),
0, 0, Math.sin(theta), Math.cos(theta)
);
}
Insert cell
function cliffordTorus(u, v) {
const [[r1, r2]] = values;
return new THREE.Vector4(
r1 * Math.cos(u) * (Math.PI / 180),
r1 * Math.sin(u) * (Math.PI / 180),
r2 * Math.cos(v) * (Math.PI / 180),
r2 * Math.sin(v) * (Math.PI / 180)
);
}
Insert cell
function project(v) {
const denom = 1 - v.w;
return new THREE.Vector3(v.x / denom, v.y / denom, v.z / denom);
}
Insert cell
function toEq(theta) {
return (u_, v_, target) => {
const u = u_ * 2 * Math.PI;
const v = v_ * 2 * Math.PI;

const torus = cliffordTorus(u, v);
const [[], [rx, ry, rz]] = values;

if (rx) {
const rotXW = rotateXW(theta);
torus.applyMatrix4(rotXW);
}
if (ry) {
const rotYW = rotateYW(theta);
torus.applyMatrix4(rotYW);
}
if (rz) {
const rotZW = rotateZW(theta);
torus.applyMatrix4(rotZW);
}

const projected = project(torus);
target.set(projected.x, projected.z, projected.y);
};
}
Insert cell
geometry = theta => {
const slices = values[0][2];
return new THREE.ParametricBufferGeometry(toEq(theta), slices, slices);
}
Insert cell
projected = {
return geometry => {
const material = new THREE.MeshNormalMaterial({
transparent: true,
opacity: 0.4
});
return new THREE.Mesh(geometry, material);
};
}
Insert cell
projectedOutline = {
return geometry => {
const material = new THREE.MeshBasicMaterial({
color: '#101010',
wireframe: true
});
return new THREE.Mesh(geometry, material);
};
}
Insert cell
renderer = {
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(width, height);
renderer.setPixelRatio(devicePixelRatio);
return renderer;
}
Insert cell
scene = {
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
const geom = geometry(theta);

const showMat = values[2][0];
showMat && scene.add(projected(geom));
const showMesh = values[2][1];
showMesh && scene.add(projectedOutline(geom));

return scene;
}
Insert cell
camera = {
const fov = 75;
const aspect = width / height;
const near = 0.001;
const far = 10000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.lookAt(scene.position);
camera.position.set(2, -1, -1);
return camera;
}
Insert cell
THREE = {
const THREE = (window.THREE = await require("three@0.99.0/build/three.min.js"));
await require("three@0.99.0/examples/js/controls/OrbitControls.js").catch(
() => {}
);
return THREE;
}
Insert cell
height = width / 1.5
Insert cell
scale = 400
Insert cell
import { slider } from '@bartok32/diy-inputs'
Insert cell
import { checkbox} from '@jashkenas/inputs'
Insert cell
import { inputsGroup } from '@bumbeishvili/input-groups'
Insert cell
sliderConfig = {
return {
theme: 'default-round',
background: {
type: 'double',
colors: ['#7295FF', '#efefef']
}
};
}
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