DEV Community

Patrick Hund
Patrick Hund

Posted on • Edited on

Resizing a Three.js Scene When the Browser Window Size Changes

I'm building a social media network and collaboration tool based on mind maps, documenting my work in this series of blog posts. Follow me if you're interested in what I've learned along the way about building web apps with React, Tailwind CSS, Firebase, Apollo/GraphQL, three.js and TypeScript.

The Problem

I've built a mind map that is rendered with three.js. Here's what I've got so far:

When I resize the browser's viewport (using the responsive preview feature of CodeSandbox, in this case), this happens:

First, I have a viewport size equivalent to a 13" MacBook Air. When I switch to various mobile device profiles, the mind map is cut off and not shown in the center of the viewport anymore.

The Solution

I'm going to add an window resize event listener that executes a function when the browser window resizes. This function then updates the HTML canvas element that the mind map is rendered on and tells three.js to adjust the settings of the 3D scene's camera.

The Code

Here's my code that adds the event listener, which I've added to my module initializeScene:

import { throttle } from 'lodash-es';
import setCanvasDimensions from './setCanvasDimensions';

const resizeUpdateInterval = 500;

window.addEventListener(
  'resize',
  throttle(
    () => {
      const width = window.innerWidth;
      const height = window.innerHeight;
      camera.aspect = width / height;
      camera.updateProjectionMatrix();
      renderer.setSize(width, height);
      setCanvasDimensions(renderer.domElement, width, height);
    },
    resizeUpdateInterval,
    { trailing: true }
  )
);
Enter fullscreen mode Exit fullscreen mode

I'm using throttle from the Lodash library to prevent the resizing to occur too often – this way, the 3D scene is updated every 500 milliseconds while the browser window is being resized.

Besides setting the size of the renderer with setSize, I also update the width and height of the HTML canvas element that three.js renders to.

This is done in a separate function, setCanvasDimensions:

function setCanvasDimensions(
  canvas,
  width,
  height,
  set2dTransform = false
) {
  const ratio = window.devicePixelRatio;
  canvas.width = width * ratio;
  canvas.height = height * ratio;
  canvas.style.width = `${width}px`;
  canvas.style.height = `${height}px`;
  if (set2dTransform) {
    canvas.getContext('2d').setTransform(ratio, 0, 0, ratio, 0, 0);
  }
}
Enter fullscreen mode Exit fullscreen mode

I'm using a trick here to make sure the canvas looks good on devices with a high pixel ratio, such as iPhones with Retina displays (see my previous post with details on this).

When I resize the window now, it works as one would expect:

Here's the whole project if you want to try it out:

To Be Continued…

I'm planning to turn my mind map into a social media network and collaboration tool and will continue to blog about my progress in follow-up articles. Stay tuned!

Top comments (1)

Collapse
 
noprod profile image
NOPR9D ☄️ • Edited

"prevent the resizing to occur too often"

Nice tips !
Otherwise I used the same method, so that reassures me ^^ (except the resizeUpdateInterval )