Convert 2D shape into 3D in d3.js and adjust height according to the value in ANGULAR

I made the one as you requested.

source code on github

here’s working demo: https://stackoverflow-angular-3d-chart.surge.sh/

This involved several intricate steps.

I couldn’t go any deeper from this answer because every part that I mentioned here could be hours worth tutorial. These are what I’ve felt interesting when I was working on it.

Used Stacks

EDIT: the stackblitz code is now outdated. I’ve used the most recent version for each package.

  • Three.js r143
  • D3.js v7.6.1
  • Angular.js v14

Getting Circle Grid

  • experiment note on ObservableHQ: https://observablehq.com/@rabelais/circle-inside-grids

First I’ve experimented on SVG with D3.js to get proper circle grid.

It seemed daunting but turned out very simple. I’ve slightly modified Midpoint circle algorithm to fill box grids in circular shape. It is little different from filling grids in 3d space; 2d space has top left corner as beginning of everything. In 3d space, everything starts from center.

const midPointX = gridWidth / 2;
const midPointY = gridHeight / 2;
const { midPointX, midPointY, radius } = config;

const getCollision = ({ x, y }) => {
  return (midPointX - x) ** 2 + (midPointY - y) ** 2 - radius ** 2 > 0;
}

grids filled in circular shape on SVG

Calculating Gaps

d3’s scale band supports automatic calculation of gaps and content size in responsive environment.

  const scaleBandX = d3
    .scaleBand()
    .domain(d3.range(0, config.gridWidth))
    .range([config.margin, config.svgWidth - config.margin * 2])
    .paddingInner(0.2);

  const scaleBandY = d3
    .scaleBand()
    .domain(d3.range(0, config.gridHeight))
    .range([config.margin, config.svgHeight - config.margin * 2])
    .paddingInner(0.2);

scaleBandX.bandwidth(); // width of box in 2d space
scaleBandY.bandwidth(); // height of box in 2d space
scaleBandX(boxIndex); // x position of box in 2d space with gap
scaleBandY(boxIndex); // y position of box in 2d space with gap

as D3 assumes vector calculation as normal, it was pretty easy to apply the very same method in 3D.

Expressing on 3D space

I’ve used Three.js to express everything in 3D. The app is running on Angular per request but it does not matter which frontend framework is used.

Everything about expressing 2d bar chart on 3d is very trivial. However, the dimension is different from 2d; the positions have to be swapped.

// code to make a single bar mesh
  makeBar(d: typeof gridData[0]) {
    // length and height is swapped. because camera is looking from 90 degree angle by default.
    const geo = new T.BoxGeometry(d.w, d.l, d.h, 32, 32);
    const mat = new T.MeshPhysicalMaterial({ color: 'red' });
    const mesh = new T.Mesh(geo, mat);
    mesh.position.x = d.x;
    // z and y is also swapped. because of the same reason.
    mesh.position.z = d.y;
    mesh.position.y = d.z;
    return mesh;
  }

then each element is assigned as 3d Group, to make them centered altogether.

app screenshot

EDIT: color scheme was missing. it is now added.

Leave a Comment