Search code examples
javascriptreactjscanvasfabricjs

How can I access fabric object using custom hook to add background image to canvas?


So I'm working on this editor where a user can upload an image and edit it on the canvas. To achieve this I'm using React and FabricJS. Besides everything I have tried to make an editor, FabricJS seemed to have what I want. And as FabricJS doesn't have native support for react I have been looking for a workaround to make it work with React. And I stumbled upon this answerhere and trying to use it.

This custom hook from that answer eliminates another issue which is adding multiple nested canvas wrappers.

Right now it is working fine if I just use a background color but it throws an error when I try to add a background image. Seems like the fabric object is not accessible. And I'm not sure how I can access it.

Here's the error:

TypeError: Cannot read properties of undefined (reading 'fromURL')

So I'm posting here if someone has an idea on how to add background image, or different shapes to the canvas using the fabric object but also using this hook as it eliminates nested fabric wrappers.

Here's the CodeSandbox.

Here's the code:

import { useCallback, useRef } from "react";
import { fabric } from "fabric";

const useFabric = (onChange) => {

    const fabricRef  = useRef();
    const disposeRef = useRef();

    return useCallback((node) => {
        if (node) {
             fabricRef.current = new fabric.Canvas(node);

             if (onChange) {
                  disposeRef.current = onChange(fabricRef.current);
             }

         } else if (fabricRef.current) {

              fabricRef.current.dispose();

              if (disposeRef.current) {
                   disposeRef.current();
                   disposeRef.current = undefined;
              }
         }
     }, []);

};


export default function App() {

     const ref = useFabric((fabricCanvas) => {

           fabricCanvas.backgroundColor = "green";

           // fabricCanvas.Image.fromURL("https://i.imgur.com/8zvUjul.jpg", function ( img ) {
           //     fabricCanvas.add(img);
           //     fabricCanvas.sendToBack(img);
           // });

          fabricCanvas.renderAll();
     });

     return (
         <div>
             <canvas ref={ref} id="canvas" />
         </div>
     );
}


Solution

  • You're calling .Image.FromUrl to the canvas instance not the fabric object.

    Try

    fabric.Image.fromUrl...

    instead of

    fabricCanvas.Image.fromURL