Когда я загружаю элементы холста Fabric.js из JSON, они не видны на холсте

В моем приложении я хотел бы поддерживать состояние холста между полноэкранным и внутристраничным режимами. Прямо сейчас я пытаюсь добиться этого, сохраняя объекты холста в формате JSON в контексте холста. При переключении режима создается новый экземпляр холста, и я загружаю объекты из JSON в этот новый экземпляр холста.

Проблема в том, что объекты не отображаются. Когда я регистрирую объекты экземпляра холста после выполнения этой загрузки JSON, я вижу, что они присутствуют внутри холста. Однако они просто не видны на холсте, когда я смотрю на страницу.

Я неправильно загружаю JSON? Новый холст, скорее всего, будет иметь другой размер, чем старый, но дело не в том, что объекты растянуты или искажены, их просто нет. Даже когда я возвращаюсь к старому размеру холста, ничего не видно.

В документации об этом ничего не упоминается, и я больше никого не нашел с этой проблемой.

Ниже приведен мой код, ограниченный тем, что имеет отношение к проблеме.

Я визуализирую холст сразу после загрузки элементов JSON.

import { useCanvas } from "@/contexts/CanvasContext";
import React, { useEffect, useRef, useState } from "react";

declare global {
  interface Window {
    fabric: any;
  }
}

type FabricCanvasProps = {
  dimensions: { width: number; height: number };
  canvasInstance: any;
  setCanvasInstance: (canvasInstance: any) => void;
};

const FabricCanvas: React.FC<FabricCanvasProps> = ({
  dimensions,
  canvasInstance,
  setCanvasInstance,
}) => {
  const canvasRef = useRef<HTMLCanvasElement | null>(null);
  const [prevDimensions, setPrevDimensions] = useState({ width: 0, height: 0 });

  const {
    activeTool,
    setIsDrawnOn,

    canvasData,
    setCanvasData,
  } = useCanvas();

  useEffect(() => {
    const fabricScriptLoaded = () => !!window.fabric;

    if (canvasRef.current && !canvasInstance && fabricScriptLoaded()) {
      const instance = new window.fabric.Canvas(canvasRef.current, {
        isDrawingMode: activeTool !== null,
        height: dimensions.height,
        width: dimensions.width,
        selection: false,
      });

      if (canvasData) {
        instance.loadFromJSON(canvasData, instance.renderAll.bind(instance));
        console.info(canvasData);
        console.info(instance.getObjects());
      }

      // Listen for changes to the canvas
      const updateDrawnState = () => {
        setIsDrawnOn(true);
      };

      instance.on("object:added", updateDrawnState);
      instance.on("object:modified", updateDrawnState);

      setCanvasInstance(instance);
    }
  }, []); // Initializes the canvas instance only once

  // Updates the context with most recent canvas data for re-rendering
  useEffect(() => {
    if (canvasInstance) {
      // Listen for any change that should update the canvas data
      const onChange = () => {
        setCanvasData(canvasInstance.toJSON());
      };

      canvasInstance.on("object:added", onChange);
      canvasInstance.on("object:modified", onChange);
      canvasInstance.on("object:removed", onChange);

      return () => {
        canvasInstance.off("object:added", onChange);
        canvasInstance.off("object:modified", onChange);
        canvasInstance.off("object:removed", onChange);
      };
    }
  }, [canvasInstance]);

// ... Some more useEffects that have to do with canvas size


  return (
    <>
      <canvas ref = {canvasRef} className = "w-full h-full" />
    </>
  );
};

export default FabricCanvas;

🤔 А знаете ли вы, что...
React обеспечивает реактивное обновление интерфейса при изменении состояния.


101
1

Ответ:

Решено

В конце концов я понял это: на самом деле это было связано с обновлениями холста, которые, как я думал, не были связаны. Я использовал следующий код для изменения размера объектов на холсте при изменении размера страницы:

  const scaleX = dimensions.width / prevDimensions.width;
  const scaleY = dimensions.height / prevDimensions.height;

  canvasInstance.getObjects().forEach((obj: any) => {
    obj.scaleX *= scaleX;
    obj.scaleY *= scaleY;
    obj.left *= scaleX;
    obj.top *= scaleY;
    obj.setCoords();
  }

Но когда компонент первоначально визуализировался, мои prevDimensions были равны 0. Это привело к тому, что объекты масштабировались до бесконечных размеров, при этом не возникало никаких ошибок или указаний на то, что что-то не так, поэтому я не мог их видеть.

Я исправил это, добавив проверку, чтобы убедиться, что здесь не происходит деления на 0.


Интересные вопросы для изучения

React (18.2.0) меняет URL-адрес с помощью навигации, но страница не обновляетсяПолучение модуля «реагировать-маршрутизатор-дом» не имеет экспортированного члена. Ошибка RouteComponentProps при переходе на реактивный маршрутизатор v6При использовании PDF React Renderer изображения не отображаются при загрузкеПринудительно использовать то же имя импортированного компонента, что и файл, из которого он импортирован, в ответ на импорт модулей TS?Есть ли способ решить проблему комбинации маршрутов, которые влияют друг на друга?Когда тип литерала шаблона с заполнителями расширяет другой?Кто-нибудь знает об этом пространстве имен «global.Express» не имеет члена «Multer» Exported.ts(2694)Получение модуля «реагировать-маршрутизатор-дом» не имеет экспортированного члена. Ошибка RouteComponentProps при переходе на реактивный маршрутизатор v6Есть ли способ решить проблему комбинации маршрутов, которые влияют друг на друга?Как получить вложенный массив indexOf в любом массиве?