Published
Edited
Oct 3, 2020
Importers
Insert cell
md`# 3D-Utils`
Insert cell
import { getSVG, drawLine, drawPath } from '@nuuuwan/svg-utils'
Insert cell
import { addDefaults } from '@nuuuwan/option-utils'
Insert cell
function rotate([x, y, z], theta) {
return [
x * Math.cos(theta) - y * Math.sin(theta),
x * Math.sin(theta) + y * Math.cos(theta),
z
];
}
Insert cell
rotate([100, 100, 100], 0.1)
Insert cell
function transform([x, y, z], transformParams) {
[x, y, z] = rotate([x, y, z], transformParams.alpha);
[y, z, x] = rotate([y, z, x], transformParams.beta);
[z, x, y] = rotate([z, x, y], transformParams.gamma);
return [x + transformParams.x0, y + transformParams.y0];
}
Insert cell
transform([100, 100, 100], { alpha: 0.1, beta: 0, gamma: 0, x0: 0, y0: 0 })
Insert cell
function getSVG3D(options) {
options = addDefaults(
options,
Object({
height: 200,
width: 200,
transformParams: Object({
alpha: 0,
beta: 0,
gamma: 0,
x0: 100,
y0: 100
})
})
);

const svg = getSVG(options);
return [svg, options.transformParams];
}
Insert cell
function drawSVG3D(svg3D) {
const [svg, transformParams] = svg3D;
return svg.node();
}
Insert cell
function draw3DLine(svg3D, [x1, y1, z1], [x2, y2, z2], options = {}) {
const [svg, transformParams] = svg3D;
const [u1, v1] = transform([x1, y1, z1], transformParams);
const [u2, v2] = transform([x2, y2, z2], transformParams);
drawLine(svg, [u1, v1], [u2, v2], options);
}
Insert cell
{
const svg3D = getSVG3D(
Object({
height: 500,
width: 500,
transformParams: { alpha: 0.1, beta: 0.2, gamma: 0.3, x0: 100, y0: 100 }
})
);
draw3DLine(svg3D, [0, 0, 0], [0, 0, 100]);
draw3DLine(svg3D, [0, 0, 0], [0, 100, 0]);
draw3DLine(svg3D, [0, 0, 0], [100, 0, 0]);
return drawSVG3D(svg3D);
}
Insert cell
function draw3DPath(svg3D, xyzList, options = {}) {
const [svg, transformParams] = svg3D;
const xyList = xyzList.map(([x, y, z]) =>
transform([x, y, z], transformParams)
);
return drawPath(svg, xyList, options);
}
Insert cell
{
const DIM = 700;
const theta = Math.PI / 6;
const svg3D = getSVG3D(
Object({
height: DIM,
width: DIM,
transformParams: {
alpha: 0,
beta: theta,
gamma: -theta,
x0: 100,
y0: DIM / 2
}
})
);

const [sx, sy, sz] = [300, 50, 50];
draw3DPath(svg3D, [[0, 0, 0], [sx, 0, 0], [sx, sy, 0], [0, sy, 0]]);

draw3DPath(svg3D, [[0, 0, 0], [sx, 0, 0], [sx, 0, sz], [0, 0, sz]]);

draw3DPath(svg3D, [[0, 0, 0], [0, sy, 0], [0, sy, sz], [0, 0, sz]]);

return drawSVG3D(svg3D);
}
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