Published
Edited
Jun 4, 2022
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
camera = [0, 0, 0]
Insert cell
projectionPlane = [
[0, 0, planeZ],
[1, 0, planeZ],
[0, 1, planeZ]
]
Insert cell
{
// draw bg
ctx.fillStyle = palette.bg;
ctx.fillRect(0, 0, width, height);

drawPts(ctx, twoDData, { fill: palette.fg });
}
Insert cell
function drawPts(ctx, data, opts = {}) {
const { fill, r } = Object.assign(
{
fill: "#fff",
r: 0.75
},
opts
);
ctx.beginPath();
ctx.fillStyle = fill;
const marginX = 0;
data.forEach((pt) => {
const [x0, y0] = pt.position;
const x = x0 + width / 2;
const y = y0 + height / 2;
ctx.moveTo(x, y);
ctx.arc(x, y, r, 0, 2 * Math.PI);
});
ctx.fill();
}
Insert cell
threeDData = {
const count = 9;
let pts = math
.linspace(count, true)
.flatMap((w) =>
math
.linspace(count, true)
.flatMap((v) =>
math
.linspace(count, true)
.map((u) => [2 * u - 1, 2 * v - 1, 2 * w - 1])
)
);

pts = pts.map((pt) => GLVec3.scale([], pt, scaling));

pts = pts.map((pt) => GLVec3.rotateY([], pt, [0, 0, 0], -rotateV * Math.PI));
pts = pts.map((pt) => GLVec3.rotateX([], pt, [0, 0, 0], rotateU * Math.PI));

pts = pts.map((pt) => {
const [x, y, z] = pt;
return [x, y, z + projectionPlane[0][2] + 1000];
});

return pts;
}
Insert cell
twoDData = {
return threeDData
.map((vec3) => {
const vec3Projected = project(vec3, projectionPlane, camera);
const distToProjectPlane = distance(vec3, vec3Projected);
const [x, y, z] = vec3Projected;
if (x < -width / 2 || x > width / 2) return false;
if (y < -height / 2 || y > height / 2) return false;
if (distToProjectPlane > frustum) return false;
if (projectionPlane[2] < z) return false;
return {
position: [x, y]
};
})
.filter(Boolean);
}
Insert cell
function project(pt, plane, camera) {
const d = distance(camera, [0, 0, plane[0][2]]);
const [x, y, z] = pt;

return [(x * d) / z, (y * d) / z, z];
}
Insert cell
viewport = ({
width,
height
})
Insert cell
palette = ({
bg: `hsl(0,0%,5%)`,
fg: `hsl(0,0%,95%)`,
debug: `hsl(300, 100%, 50%)`
})
Insert cell
Insert cell
Insert cell
Insert cell
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