Public
Edited
May 29, 2024
Fork of Simple D3
Insert cell
Insert cell
viewof btn = html`<button>update</button>`
Insert cell
chart = {
const width = 960;
const height = 500;
const startAngle = Math.PI / 6;
const origin = { x: 480, y: 250 };
const colorScale = d3.scaleOrdinal(d3.schemeDark2);
const j = 10;
let scale = 20;
let cubesData = [];
let alpha = 0;
let beta = 0;
let mx, my, mouseX = 0, mouseY = 0;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.attr("style", "max-width: 100%; height: auto;")
.call(d3.drag().on("drag", dragged) .on("start", dragStart) .on("end", dragEnd));

const cubesGroup = svg.append("g").attr("class", "cubes");

const cubes3d = d33d.cubes3D()
.rotateY(startAngle)
.rotateX(-startAngle)
.origin(origin)
.scale(scale);

function drawChart(data, tt = 0) {
const cubes = cubesGroup
.selectAll("g.cube")
.data(data, (d) => d.id);

const ce = cubes
.enter()
.append("g")
.attr("class", "cube")
.attr("fill", (d) => colorScale(d.id))
.attr("stroke", (d) => d3.color(colorScale(d.id)).darker(2))
.merge(cubes)
.sort(cubes3d.sort);

cubes.exit().remove();

const faces = cubes.merge(ce).selectAll("path.face").data(
(d) => d.faces,
(d) => d.face
);

faces
.enter()
.append("path")
.attr("class", "face")
.attr("fill-opacity", 0.95)
.classed("d3-3d", true)
.merge(faces)
.transition()
.duration(tt)
.attr("d", cubes3d.draw);
faces.exit().remove();

const texts = cubes.merge(ce).selectAll("text.text").data((d) => {
const t = d.faces.filter((d) => d.face === "top");
return [{ height: d.height, centroid: t[0].centroid }];
});
texts
.enter()
.append("text")
.attr("class", "text")
.attr("dy", "-.7em")
.attr("text-anchor", "middle")
.attr("font-family", "system-ui, sans-serif")
.attr("font-weight", "bolder")
.attr("x", (d) => origin.x + scale * d.centroid.x)
.attr("y", (d) => origin.y + scale * d.centroid.y)
.classed("d3-3d", true)
.merge(texts)
.transition()
.duration(tt)
.attr("fill", "black")
.attr("stroke", "none")
.attr("x", (d) => origin.x + scale * d.centroid.x)
.attr("y", (d) => origin.y + scale * d.centroid.y)
.tween("text", function (d) {
const that = d3.select(this);
const i = d3.interpolateNumber(+that.text(), Math.abs(d.height));
return function (t) {
that.text(i(t).toFixed(1));
};
});

texts.exit().remove();

ce.selectAll(".d3-3d").sort(cubes3d.sort);
}

function init() {
cubesData = [];
let cnt = 0;
for (let z = -j / 2; z <= j / 2; z = z + 5) {
for (let x = -j; x <= j; x = x + 5) {
const h = d3.randomUniform(-2, -7)();
const cube = makeCube(h, x, z);
cube.id = `cube-${cnt++}`;
cube.height = h;
cubesData.push(cube);
}
}
drawChart(cubes3d(cubesData), 1000);
}

function dragStart(event) {
mx = event.x;
my = event.y;
}

function dragged(event) {
beta = (event.x - mx + mouseX) * (Math.PI / 230);
alpha = (event.y - my + mouseY) * (Math.PI / 230) * -1;
drawChart(
cubes3d.rotateY(beta + startAngle).rotateX(alpha - startAngle)(cubesData)
);
}

function dragEnd(event) {
mouseX = event.x - mx + mouseX;
mouseY = event.y - my + mouseY;
}

init();

viewof btn.addEventListener("click", init);
return svg.node();
}
Insert cell
function makeCube(h, x, z) {
return [
{ x: x - 1, y: h, z: z + 1 }, // FRONT TOP LEFT
{ x: x - 1, y: 0, z: z + 1 }, // FRONT BOTTOM LEFT
{ x: x + 1, y: 0, z: z + 1 }, // FRONT BOTTOM RIGHT
{ x: x + 1, y: h, z: z + 1 }, // FRONT TOP RIGHT
{ x: x - 1, y: h, z: z - 1 }, // BACK TOP LEFT
{ x: x - 1, y: 0, z: z - 1 }, // BACK BOTTOM LEFT
{ x: x + 1, y: 0, z: z - 1 }, // BACK BOTTOM RIGHT
{ x: x + 1, y: h, z: z - 1 }, // BACK TOP RIGHT
];
}
Insert cell
d33d = require("https://unpkg.com/d3-3d/build/d3-3d.min.js")
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