Ensuring that a canvas remains centered and completely visible within its parent element while zooming in React

Currently, I am developing a straightforward PowerPoint creator using React. In this project, I have integrated a zoom feature for a canvas element. The principle is that the canvas should resize based on a scale factor. However, there seems to be an issue. When the canvas extends beyond its parent container, the left and top sides of the canvas become invisible when scrolling. Surprisingly, only the right and bottom edges are visible.

Explore Demo

Answer №1

The issue you're facing is related to how the scaling and scrolling behavior is managed within your React component. When the canvas element scales up, it goes beyond the boundaries of its parent container, but only the bottom and right edges are scrollable while the left and top edges are not. This occurs due to the handling of CSS overflow and scaling.

To fix this problem, consider making the following adjustments:

Make sure the size of the parent container is fixed or properly controlled to allow scrolling in all directions. Position the canvas correctly inside the parent container to ensure it remains centered when scaled. Modify the overflow settings to handle the scaled canvas appropriately.

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

export default function App() {
  const canvasRef = useRef(null);
  const parentRef = useRef(null);
  const [scale, setScale] = useState(1);

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

    canvas.width = 800 * scale;
    canvas.height = 450 * scale;

    canvas.style.width = `${800 * scale}px`;
    canvas.style.height = `${450 * scale}px`;

    draw(ctx, scale);
  }, [scale]);

  const draw = (context, scale) => {
    context.clearRect(0, 0, context.canvas.width, context.canvas.height);
    context.save();
    context.fillStyle = "red";
    context.fillRect(100 * scale, 100 * scale, 200 * scale, 100 * scale);
    context.restore();
  };

  const onZoom = (add) => {
    setScale((prev) => prev + add);
  };

  return (
    <div
      ref={parentRef}
      style={{
        // height: "100vh",
        // width: "100vw",
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        flexDirection: "column",
        // overflow: "auto",
      }}
    >
      <div
        style={{
          height: "100vh",
          width: "100vw",
          overflow: "scroll",
        }}
      >
        <canvas
          ref={canvasRef}
          style={{ border: "2px solid red" }}
          width={800}
          height={450}
        >
          Drawing canvas
        </canvas>
      </div>
      <div>
        <button onClick={() => onZoom(0.1)}>+</button>
        <button onClick={() => onZoom(-0.1)}>-</button>
      </div>
    </div>
  );
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can you explain the distinction between escapeXml and escapeHtml functions?

When it comes to escaping characters in JSP pages, I am wondering which is the better option - using escapeXml or escapeHtml? ...

Two-column dropdowns without the use of tables

I am looking to create a drop-down menu with the following structure: | Heading ---------------- action | Item action | Item action | Item action | Item The action could represent "Change" and Item could be something like "Users". To maintain ...

Error: Unable to locate module 'fs' within the Next.js application

I am having trouble figuring out the issue in my next.js app. The fs module is a default file system module of nodejs, but I am getting an error saying module not found. https://i.sstatic.net/5uh8o.png https://i.sstatic.net/87u5o.png ...

The html button adorned with a variety of CSS styles

I've been attempting to create a button for a message system that displays an orange dot when there's a new message, but I'm having trouble getting it to work. Do you think it's possible? Check out the button below: <input type="bu ...

Submitting a form using Ajax that was generated with the help of jQuery

Using a table with various rows, each row has an edit button. Upon clicking the edit button, a form is generated using ajax/json to populate the form data based on the selected row. An issue arises when setting up the ajax for this form. Although the met ...

Why does the hashtag keep popping up every time I launch the Bootstrap Modal?

I can't figure out why this keeps happening. I researched how to eliminate hashtags from the URL and found multiple solutions. However, none of them proved to be helpful as they only removed the hashtag, requiring a page refresh which still didn' ...

Incorporating an external SVG link into a React application

While I may not be an SVG expert, I haven't encountered any issues with loading SVGs in my React app so far. I prefer using the svg tag over the image tag because sizing tends to present problems with the latter option when working with external links ...

How to efficiently update a child component in React using UseState and establish a connection back to the parent component

I am currently working on developing a prototype for a master/detail scenario in React and Material-UI. The task involves creating a basic list of objects with the ability to edit and save an item using a dialog. While I have successfully updated the visit ...

Error in TypeScript React: "Could not locate module: Unable to locate 'styled-components'"

Even though I have installed the @types/styled-components package and compiled my Typescript React app, I am consistently encountering this error: Module not found: Can't resolve 'styled-components' I have double-checked that 'style ...

JavaScript: Locate the HTML Attribute that Matches an ID

If you want to use just JavaScript, without relying on libraries like JQuery, how can you retrieve the data attribute associated with a specific Id? For example: <div id="id-test" data-qa="data-qa-test"> </div> Input: &quo ...

What steps can be taken to resolve the TS5023 error that arises when including "allowImportingTsExtensions" in the tsconfig.json file?

While working on my React project, I've encountered a specific error that reads: Could not parse tsconfig.json. Please ensure it contains valid JSON syntax. Details: error TS5023: Unknown compiler option 'allowImportingTsExtensions'. I tr ...

Tips on showing the "Clear" text on the left side of the calendar in MUI DatePicker

My challenge involves using DesktopDatePicker from material-ui(version 5.0.0) and attempting to show the text "Clear" on the left side of the calendar. import * as React from "react"; import dayjs from "dayjs"; import TextField from &qu ...

The current Webpack configuration for production fails to account for importing CSS files

I am struggling to figure out how to properly load a static site that is not located in the root folder: let HWPTest = new HtmlWebpackPlugin({ template: __dirname + "/src/artists/test.html", filename: 'artists/test.html', favicon: &apos ...

The drawbacks of using toJS() in React Redux: Is it really necessary in mapStateToProps()?

After reading through the Redux documentation, I came across a recommendation to not use Immutable with Redux. This advice has left me feeling confused. Why should I avoid using toJS() in the mapStateToProps function? It seems that React already uses Dee ...

Understanding the extent of variables in Javascript

I'm struggling to comprehend the scope of 'this' in this particular situation. I can easily call each of these functions like: this.startTracking(); from within the time tracker switch object. However, when attempting to execute the code: Dr ...

Design an HTML button/label with text and a starting width of zero

I'm attempting to design HTML buttons and labels with text that initially have zero width. Once inserted, they should smoothly transition to a visible state. I've tried adjusting the initial width and min-width style properties without success. ...

Issue with by.cssContainingText function not performing as intended

I have a container that I want to be able to click on. Here's how it looks: <div class="CG-Item CG-B-Left ng-binding" ng-bind="SPL.showTitleText">My New SPL</div> So I am trying to use this code to click on it: element(by.cssContainingT ...

Post-installation of NPM, configuring CA certificates on Windows system

TLDR; Is there a way to seamlessly set NODE_EXTRA_CA_CERTS in a Windows environment for NPM packages' post-install scripts without requiring system changes, configuration file modifications, or admin-level permissions? Details This issue has been f ...

Execute action based on local state when component is unmounted in React

I have encountered an issue with a component's internal state not being properly propagated throughout the application, specifically under certain events. const FunComponent = (initialDescription, onSave) => { const [description, setDescription] ...

In order to manage this specific file type, you may require a suitable loader. React in conjunction with Material UI could be the

I recently created a project using Material UI and React JS, but I encountered a puzzling error without making any changes to my app. Despite reaching out for help by creating an issue on MUI, I received no response. The app was generated using npx-create ...