Public
Edited
Apr 17, 2024
Fork of Three.js
7 stars
Insert cell
Insert cell
Insert cell
renderer.domElement
Insert cell
// Stats.domElement
Insert cell
// Continuously updates
{
while (true) {
cube.rotation.z += 0.01;
renderer.render(scene, camera);
dotCloudMesh.rotateX(0.01);
// Stats.update();
yield null;
}
}
Insert cell
height = 600
Insert cell
cube = {
const material = new THREE.MeshNormalMaterial();
const geometry = new THREE.BoxGeometry(1, 1, 1);
const cube = new THREE.Mesh(geometry, material);
return cube;
}
Insert cell
dotCloudMesh = {
const dotCloudTriangles = 2e5,
curveTriangles = 1e5;

const geometry = new THREE.BufferGeometry();

const positions = [];
const normals = [];
const colors = [];

const color = new THREE.Color();

const xEnlarge = 2;

const pA = new THREE.Vector3();
const pB = new THREE.Vector3();
const pC = new THREE.Vector3();

const cb = new THREE.Vector3();
const ab = new THREE.Vector3();

let rndX = d3.randomUniform(d3.max(data, (d) => d.x)),
rndR = d3.randomUniform(-1, 1),
rndTheta = d3.randomUniform(2 * Math.PI),
rndDotSize = d3.randomUniform(-0.005, 0.005),
x,
y,
z,
r,
d,
d1,
d2,
theta;

function addDot(x, y, z, alpha = undefined) {
const ax = x + rndDotSize();
const ay = y + rndDotSize();
const az = z + rndDotSize();

const bx = x + rndDotSize();
const by = y + rndDotSize();
const bz = z + rndDotSize();

const cx = x + rndDotSize();
const cy = y + rndDotSize();
const cz = z + rndDotSize();

positions.push(ax, ay, az);
positions.push(bx, by, bz);
positions.push(cx, cy, cz);

// flat face normals

pA.set(ax, ay, az);
pB.set(bx, by, bz);
pC.set(cx, cy, cz);

cb.subVectors(pC, pB);
ab.subVectors(pA, pB);
cb.cross(ab);

cb.normalize();

const nx = cb.x;
const ny = cb.y;
const nz = cb.z;

normals.push(nx, ny, nz);
normals.push(nx, ny, nz);
normals.push(nx, ny, nz);

// colors

const vx = x + 0.5;
const vy = y + 0.5;
const vz = z + 0.5;

color.setRGB(vx, vy, vz);

alpha = alpha ? alpha : Math.random();

colors.push(color.r, color.g, color.b, alpha);
colors.push(color.r, color.g, color.b, alpha);
colors.push(color.r, color.g, color.b, alpha);
}

for (let i = 0; i < dotCloudTriangles; i++) {
// positions
x = rndX();
d = data.find((d) => d.x > x);
r = d ? d.r : 0;
r *= rndR();
theta = rndTheta();
y = Math.cos(theta) * r;
z = Math.sin(theta) * r;
x -= 0.5;
x *= xEnlarge;

addDot(x, y, z);
}

for (let i = 0; i < curveTriangles; ++i) {
x = rndX();
d1 = data.findLast((d) => d.x < x);
d2 = data.find((d) => d.x > x);

if ((d1 === undefined) & (d2 === undefined)) {
y = 0;
z = 0;
} else if (d1 === undefined) {
y = d2.y;
z = d2.h;
} else if (d2 === undefined) {
y = d1.y;
z = d1.h;
} else {
y = d3.scaleLinear().domain([d1.x, d2.x]).range([d1.y, d2.y])(x);
z = d3.scaleLinear().domain([d1.x, d2.x]).range([d1.h, d2.h])(x);
}
x -= 0.5;
x *= xEnlarge;
addDot(x, y, z, 1);
}

function disposeArray() {
this.array = null;
}

geometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(positions, 3).onUpload(disposeArray)
);
geometry.setAttribute(
"normal",
new THREE.Float32BufferAttribute(normals, 3).onUpload(disposeArray)
);
geometry.setAttribute(
"color",
new THREE.Float32BufferAttribute(colors, 4).onUpload(disposeArray)
);

geometry.computeBoundingSphere();

const material = new THREE.MeshPhongMaterial({
color: 0xd5d5d5,
specular: 0xffffff,
shininess: 250,
side: THREE.DoubleSide,
vertexColors: true,
transparent: true
});

const mesh = new THREE.Mesh(geometry, material);

return mesh;
}
Insert cell
scene = {
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x001b42);

// scene.add(cube);

scene.add(dotCloudMesh);

scene.fog = new THREE.Fog(0x050505, 2000, 3500);
scene.add(new THREE.AmbientLight(0xcccccc));

const light1 = new THREE.DirectionalLight(0xffffff, 1.5);
light1.position.set(1, 1, 1);
scene.add(light1);

const light2 = new THREE.DirectionalLight(0xffffff, 4.5);
light2.position.set(0, -1, 0);
scene.add(light2);

return scene;
}
Insert cell
camera = {
const fov = 45;
const aspect = width / height;
const near = 1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(2, 2, -2);
camera.position.set(1, -1.3, 3);
camera.lookAt(new THREE.Vector3(0, 0, 0));
return camera;
}
Insert cell
renderer = {
const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(width, height);
renderer.setPixelRatio(devicePixelRatio);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.addEventListener("change", () => renderer.render(scene, camera));
invalidation.then(() => (controls.dispose(), renderer.dispose()));
return renderer;
}
Insert cell
Stats = {
let module, stats;
module = await import(
"https://threejs.org/examples/jsm/libs/stats.module.js"
);
stats = module.default();

stats.domElement.style.position = "";

return stats;
}
Insert cell
THREE = {
const THREE = window.THREE = await require("three@0.130.0/build/three.min.js");
await require("three@0.130.0/examples/js/controls/OrbitControls.js").catch(() => {});
return THREE;
}
Insert cell
Insert cell
data = {
return mkHilbertData(500, nOctaves);
}
Insert cell
data
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
import { mkHilbertData } from "@listenzcc/hilbert-transform"
Insert cell
d3 = require("d3")
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