Home > Enterprise >  Resizing a canvas element when browser window size changes
Resizing a canvas element when browser window size changes

Time:12-06

I am trying to create a web page with the following layout using React:

  • A top bar
  • A side bar on the right
  • A canvas element filling the remaining screen space

The elements should fill the page width and height exactly and respond to change of the browser window size.

I can achieve this behavior using a flexbox, but the canvas content is extremely blurry.

This can be solved by setting the canvas resolution to it's dimensions inside an useEffect callback like this:

canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;

However, this stops the canvas from responding to the resizing of the page - more specifically, the canvas aspect ratio does not follow the page dimensions when the page size increases and it does not change at all when the page size decreases.

I created two examples to illustrate the issue:

  1. This example (CodeSandbox) does not have blurry canvas content because I set the canvas resolution using the code snippet above, but does not respond to page resizing.
  2. This example (CodeSandbox) responds to page resizing but the canvas content is blurry.

Do you have any suggestions how to reconcile this behavior? I have seen similar questions asked here but none of the examples actually worked.

CodePudding user response:

Did you try to setting the canvas height and width before getting the context:

  useEffect(() => {
    let canvas = canvasRef.current;
    canvas.width = canvas.offsetWidth;
    canvas.height = canvas.offsetHeight;
    const context = canvas.getContext("2d");
    window.requestAnimationFrame(() => {
      draw(context, canvas);
    });
  }, [timer]);

I recommend you to use window.requestAnimationFrame since you are re-redering the component multiples times to perform an animation

Working example: https://codesandbox.io/s/react-playground-forked-upojf8?file=/plot.js:806-1079

CodePudding user response:

It sounds like you are looking for a way to make your canvas element fill the remaining screen space and respond to changes in the browser window size without losing resolution.

One solution would be to use CSS to set the canvas element to width: 100% and height: 100%, and then use JavaScript to listen for the window resize event. Inside the event listener, you can update the width and height of the canvas element to match the current size of the window. This will ensure that the canvas element fills the screen and maintains its aspect ratio when the window is resized.

Here is an example of how you could implement this:

import React, { useRef, useEffect } from "react";

function App() {
  const canvasRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext("2d");

    // Set the initial canvas dimensions
    canvas.width = canvas.offsetWidth;
    canvas.height = canvas.offsetHeight;

    // Draw something on the canvas
    ctx.fillStyle = "#FF0000";
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // Listen for window resize events and update the canvas dimensions
    window.addEventListener("resize", () => {
      canvas.width = canvas.offsetWidth;
      canvas.height = canvas.offsetHeight;
    });
  }, []);

  return (
    <div style={{ width: "100%", height: "100%" }}>
      <canvas ref={canvasRef} style={{ width: "100%", height: "100%" }} />
    </div>
  );
}

I hope this helps! Let me know if you have any other questions.

  • Related